Compare commits

...

16 Commits

Author SHA1 Message Date
Developer 02
87e4c1414e Enhance ConfigureGlobalExceptionHandler method
Updated the `ConfigureGlobalExceptionHandler` method in the `DependencyInjection` class to include two optional parameters: `options` (nullable) and `addDefaultHandlers` (defaulting to true). The method now initializes `options` to a default action if null and adds default exception handlers when `addDefaultHandlers` is true, improving flexibility and usability.
2025-05-19 16:45:40 +02:00
Developer 02
fd8e976e1e Refactor HttpExceptionHandler to use properties
Changed DefaultBadRequest, DefaultNotFound, and Default
from readonly fields to properties for lazy evaluation,
enhancing performance and flexibility while maintaining
the same functionality.
2025-05-19 16:18:05 +02:00
Developer 02
2c393701e4 Add NuGet package metadata and asset inclusion
Updated `DigitalData.Core.Exceptions.Middleware.csproj` to include essential NuGet package metadata such as `PackageId`, `Authors`, `Description`, and versioning information. Added an `ItemGroup` for the `core_icon.png` asset to ensure it is packed with the NuGet package. Retained existing framework-specific references for `Microsoft.Extensions.Options` for `net7.0` and `net8.0`.
2025-05-19 16:09:45 +02:00
Developer 02
1d50fd8e5b Update NuGet metadata and project build configurations
Enhanced `DigitalData.Core.Exceptions.csproj` with NuGet package metadata including `PackageId`, `Authors`, `Description`, and versioning details. Added `core_icon.png` asset to the package.

Modified `DigitalData.Core.sln` to change project build configurations from `Debug` to `Release` for multiple projects.
2025-05-19 15:58:27 +02:00
Developer 02
701c34a251 Add assets project and update legacy icon
This commit introduces a new project named "assets" to the solution, which includes two assets: "core_icon.png" and "core_legacy_icon.png". Additionally, the file `core_legacy_icon.png` has been completely replaced with a new version, featuring a different binary structure and likely a new visual design.
2025-05-19 15:34:17 +02:00
Developer 02
63f914d188 Refactor CRUDRepository for improved flexibility
- Added using directives for new application interfaces.
- Removed constraint for IUnique<TId> from TEntity.
- Updated CountAsync method to use GetId() for identifier retrieval.
2025-05-19 15:27:08 +02:00
Developer 02
9ea2599553 Remove DependencyInjection class and global exception handler
The entire `DependencyInjection` class has been removed, including the `UseGlobalExceptionHandler` extension method and its associated `using` directive. This change eliminates the functionality for setting up global exception handling middleware in the application.
2025-05-19 15:25:59 +02:00
Developer 02
b8995da5ea Refactor global exception handling middleware
Updated `GlobalExceptionHandlerMiddleware.cs` to include
necessary using directives for logging and options handling.
Removed the `HandleExceptionAsync` method and replaced it
with a more extensible approach using a dictionary of
handlers for different exception types. Added logging for
unhandled exceptions to ensure proper error tracking.
2025-05-19 15:21:11 +02:00
Developer 02
14013bc7b7 Add default handlers to HttpExceptionHandler
Introduce static methods for creating HttpExceptionHandler instances for specific exceptions. Define default message factory and handlers for common HTTP status codes, including a generic handler that returns a JSON response for internal server errors.
2025-05-19 15:06:24 +02:00
Developer 02
f586e9eb2f Refactor exception handling to use HttpExceptionHandler
Updated GlobalExceptionHandlerOptions to replace HttpExceptionMapping with HttpExceptionHandler. Removed HttpExceptionMapping class and introduced HttpExceptionHandler for managing exceptions in HTTP requests. Added methods for creating specific exception handlers and default handlers for common exceptions, with JSON serialization for error messages.
2025-05-19 15:01:50 +02:00
Developer 02
ce786a6d42 Update package references in project file
Updated `DigitalData.Core.Exceptions.Middleware.csproj` to include specific `Microsoft.Extensions.Options` package references for target frameworks net7.0, net8.0, and net9.0. Removed the previous single `<ItemGroup>` and added three new `<ItemGroup>` entries with the corresponding package versions.
2025-05-19 14:41:46 +02:00
Developer 02
97695fb0b0 Add dependency injection for global exception handler
Introduce methods in DependencyInjection.cs for configuring
and using a global exception handler. Update the project file
to include a reference to Microsoft.Extensions.Options.
Modify GlobalExceptionHandlerMiddleware to accept
IOptions<GlobalExceptionHandlerOptions> for enhanced
configuration through dependency injection.
2025-05-19 14:38:49 +02:00
Developer 02
cb7b69a0a2 Refactor GlobalExceptionHandlerOptions for better access
Updated the accessibility of the RegisteredMappings field to internal and introduced a DefaultMapping property. Modified the Add method to support setting a mapping as default, with adjusted logic for adding mappings.
2025-05-19 14:30:50 +02:00
Developer 02
b38422256c Enhance HttpExceptionMapping with logging and defaults
Added optional 'Log' property to HttpExceptionMapping for
specifying logging behavior. Introduced static readonly
properties for default mappings of BadRequestException and
NotFoundException using a default message factory.
2025-05-19 14:24:10 +02:00
Developer 02
9b29a49ad6 Refactor exception handling with new mapping system
Updated `GlobalExceptionHandlerOptions` to use a new `_registeredMappings` dictionary for `HttpExceptionMapping` objects, enhancing flexibility in mapping exceptions to HTTP responses. Renamed `RegisterException` to `Add` to reflect its new functionality. Removed the `HttpResponse` record definition and introduced a new `HttpExceptionMapping` record, which includes a static `Create` method for easier instantiation of mappings.
2025-05-19 14:15:38 +02:00
Developer 02
83ba492b37 Add global exception handling middleware
Introduces `GlobalExceptionHandlerMiddleware` for managing exceptions in the request pipeline, logging them, and returning JSON error responses. A new project, `DigitalData.Core.Exceptions.Middleware`, is created to house this middleware and related classes. The `GlobalExceptionHandlerOptions` class allows for custom exception registration with specific HTTP status codes, while a new `HttpResponse` record encapsulates status codes and messages for structured responses. The middleware is registered in the `DependencyInjection` class for easy integration.
2025-05-19 13:27:37 +02:00
12 changed files with 230 additions and 102 deletions

BIN
Assets/core_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1020 KiB

BIN
Assets/core_legacy_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View File

@ -0,0 +1,26 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
namespace DigitalData.Core.Exceptions.Middleware;
public static class DependencyInjection
{
public static IServiceCollection ConfigureGlobalExceptionHandler(this IServiceCollection services, Action<GlobalExceptionHandlerOptions>? options = null, bool addDefaultHandlers = true)
{
options ??= opt => { };
if (addDefaultHandlers)
{
options += opt => opt.Add(HttpExceptionHandler.Default, setAsDefault: true);
options += opt => opt.Add(HttpExceptionHandler.DefaultBadRequest);
options += opt => opt.Add(HttpExceptionHandler.DefaultNotFound);
}
return services.Configure(options);
}
public static IApplicationBuilder UseGlobalExceptionHandler(this IApplicationBuilder app)
{
app.UseMiddleware<GlobalExceptionHandlerMiddleware>();
return app;
}
}

View File

@ -0,0 +1,46 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net7.0;net8.0;net9.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<!-- NuGet Package Metadata -->
<PackageId>DigitalData.Core.Exceptions.Middleware</PackageId>
<Authors>Digital Data GmbH</Authors>
<Company>Digital Data GmbH</Company>
<Product>DigitalData.Core.Exceptions.Middleware</Product>
<Description>Provides middleware components for standardized exception handling and error response formatting in ASP.NET Core applications.</Description>
<PackageTags>digital data core exceptions middleware</PackageTags>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Copyright>Copyright 2025</Copyright>
<PackageProjectUrl></PackageProjectUrl>
<RepositoryUrl>http://git.dd:3000/AppStd/WebCoreModules.git</RepositoryUrl>
<PackAsTool>False</PackAsTool>
<PackageIcon>core_icon.png</PackageIcon>
<Version>1.0.0</Version>
<AssemblyVersion>1.0.0</AssemblyVersion>
<FileVersion>1.0.0</FileVersion>
</PropertyGroup>
<ItemGroup>
<None Include="..\Assets\core_icon.png">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DigitalData.Core.Exceptions\DigitalData.Core.Exceptions.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,52 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace DigitalData.Core.Exceptions.Middleware;
/// <summary>
/// Middleware for handling exceptions globally in the application.
/// Captures exceptions thrown during the request pipeline execution,
/// logs them, and returns an appropriate HTTP response with a JSON error message.
/// </summary>
public class GlobalExceptionHandlerMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<GlobalExceptionHandlerMiddleware>? _logger;
private readonly GlobalExceptionHandlerOptions? _options;
/// <summary>
/// Initializes a new instance of the <see cref="GlobalExceptionHandlerMiddleware"/> class.
/// </summary>
/// <param name="next">The next middleware in the request pipeline.</param>
/// <param name="logger">The logger instance for logging exceptions.</param>
public GlobalExceptionHandlerMiddleware(RequestDelegate next, ILogger<GlobalExceptionHandlerMiddleware>? logger = null, IOptions<GlobalExceptionHandlerOptions>? options = null)
{
_next = next;
_logger = logger;
_options = options?.Value;
}
/// <summary>
/// Invokes the middleware to handle the HTTP request.
/// </summary>
/// <param name="context">The HTTP context of the current request.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context); // Continue down the pipeline
}
catch (Exception ex)
{
if(ex.GetType() == typeof(Exception))
_options?.DefaultHandler?.HandleExceptionAsync.Invoke(context, ex, _logger);
if (_options?.Handlers.TryGetValue(ex.GetType(), out var handler) ?? false)
handler?.HandleExceptionAsync.Invoke(context, ex, _logger);
}
}
}

View File

@ -0,0 +1,17 @@
namespace DigitalData.Core.Exceptions.Middleware;
public class GlobalExceptionHandlerOptions
{
internal readonly Dictionary<Type, HttpExceptionHandler> Handlers = new();
internal HttpExceptionHandler? DefaultHandler { get; private set; }
public GlobalExceptionHandlerOptions Add(HttpExceptionHandler handler, bool setAsDefault = false)
{
if (setAsDefault)
DefaultHandler = handler;
else
Handlers[handler.ExceptionType] = handler;
return this;
}
}

View File

@ -0,0 +1,42 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Net;
using System.Text.Json;
namespace DigitalData.Core.Exceptions.Middleware;
public record HttpExceptionHandler(Type ExceptionType, Func<HttpContext, Exception, ILogger?, Task> HandleExceptionAsync)
{
#region Alternative generator methods
public static HttpExceptionHandler Create<TException>(Func<HttpContext, Exception, ILogger?, Task> HandleExceptionAsync) where TException : Exception
=> new HttpExceptionHandler(typeof(TException), HandleExceptionAsync);
public static HttpExceptionHandler Create<TException>(HttpStatusCode statusCode, Func<Exception, string> messageFactory) where TException : Exception
=> Create<TException>(
async (context, ex, logger) =>
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)statusCode;
var message = messageFactory(ex);
await context.Response.WriteAsync(JsonSerializer.Serialize(new { message }));
}
);
#endregion
#region Default handlers
public static readonly Func<Exception, string> DefaultMessageFactory = ex => ex.Message;
public static HttpExceptionHandler DefaultBadRequest => Create<BadRequestException>(HttpStatusCode.BadRequest, DefaultMessageFactory);
public static HttpExceptionHandler DefaultNotFound => Create<NotFoundException>(HttpStatusCode.NotFound, DefaultMessageFactory);
public static HttpExceptionHandler Default => Create<Exception>(
async (context, ex, logger) =>
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
var message = "An unexpected error occurred.";
await context.Response.WriteAsync(JsonSerializer.Serialize(new { message }));
});
#endregion
};

View File

@ -1,12 +0,0 @@
using Microsoft.AspNetCore.Builder;
namespace DigitalData.Core.Exceptions;
public static class DependencyInjection
{
public static IApplicationBuilder UseGlobalExceptionHandler(this IApplicationBuilder app)
{
app.UseMiddleware<GlobalExceptionHandlerMiddleware>();
return app;
}
}

View File

@ -4,8 +4,31 @@
<TargetFrameworks>net7.0;net8.0;net9.0</TargetFrameworks> <TargetFrameworks>net7.0;net8.0;net9.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<!-- NuGet Package Metadata -->
<PackageId>DigitalData.Core.Exceptions</PackageId>
<Authors>Digital Data GmbH</Authors>
<Company>Digital Data GmbH</Company>
<Product>DigitalData.Core.Exceptions</Product>
<Description>This package contains exceptions for the DigitalData.Core library</Description>
<PackageTags>digital data core exceptions</PackageTags>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Copyright>Copyright 2025</Copyright>
<PackageProjectUrl></PackageProjectUrl>
<RepositoryUrl>http://git.dd:3000/AppStd/WebCoreModules.git</RepositoryUrl>
<PackAsTool>False</PackAsTool>
<PackageIcon>core_icon.png</PackageIcon>
<Version>1.0.0</Version>
<AssemblyVersion>1.0.0</AssemblyVersion>
<FileVersion>1.0.0</FileVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<None Include="..\Assets\core_icon.png">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.3.0" /> <PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.3.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.5" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.5" />

View File

@ -1,83 +0,0 @@
namespace DigitalData.Core.Exceptions;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Net;
using System.Text.Json;
/// <summary>
/// Middleware for handling exceptions globally in the application.
/// Captures exceptions thrown during the request pipeline execution,
/// logs them, and returns an appropriate HTTP response with a JSON error message.
/// </summary>
public class GlobalExceptionHandlerMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<GlobalExceptionHandlerMiddleware>? _logger;
/// <summary>
/// Initializes a new instance of the <see cref="GlobalExceptionHandlerMiddleware"/> class.
/// </summary>
/// <param name="next">The next middleware in the request pipeline.</param>
/// <param name="logger">The logger instance for logging exceptions.</param>
public GlobalExceptionHandlerMiddleware(RequestDelegate next, ILogger<GlobalExceptionHandlerMiddleware>? logger = null)
{
_next = next;
_logger = logger;
}
/// <summary>
/// Invokes the middleware to handle the HTTP request.
/// </summary>
/// <param name="context">The HTTP context of the current request.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context); // Continue down the pipeline
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex, _logger);
}
}
/// <summary>
/// Handles exceptions by logging them and writing an appropriate JSON response.
/// </summary>
/// <param name="context">The HTTP context of the current request.</param>
/// <param name="exception">The exception that occurred.</param>
/// <param name="logger">The logger instance for logging the exception.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
private static async Task HandleExceptionAsync(HttpContext context, Exception exception, ILogger? logger = null)
{
context.Response.ContentType = "application/json";
string message;
switch (exception)
{
case BadRequestException badRequestEx:
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
message = badRequestEx.Message;
break;
case NotFoundException notFoundEx:
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
message = notFoundEx.Message;
break;
default:
logger?.LogError(exception, "Unhandled exception occurred.");
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
message = "An unexpected error occurred.";
break;
}
await context.Response.WriteAsync(JsonSerializer.Serialize(new
{
message
}));
}
}

View File

@ -1,4 +1,5 @@
using DigitalData.Core.Abstractions; using DigitalData.Core.Abstractions;
using DigitalData.Core.Application;
using DigitalData.Core.Application.Interfaces.Repository; using DigitalData.Core.Application.Interfaces.Repository;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -15,7 +16,7 @@ namespace DigitalData.Core.Infrastructure
/// It leverages the EF Core's DbContext and DbSet to perform these operations. /// It leverages the EF Core's DbContext and DbSet to perform these operations.
/// </remarks> /// </remarks>
public class CRUDRepository<TEntity, TId, TDbContext> : ICRUDRepository<TEntity, TId> public class CRUDRepository<TEntity, TId, TDbContext> : ICRUDRepository<TEntity, TId>
where TEntity : class, IUnique<TId> where TEntity : class
where TDbContext : DbContext where TDbContext : DbContext
{ {
protected readonly TDbContext _dbContext; protected readonly TDbContext _dbContext;
@ -107,6 +108,6 @@ namespace DigitalData.Core.Infrastructure
/// If there are multiple entities with the same identifier, they will all be counted. /// If there are multiple entities with the same identifier, they will all be counted.
/// The default implementation assumes that the identifier is unique for each entity. /// The default implementation assumes that the identifier is unique for each entity.
/// </remarks> /// </remarks>
public virtual async Task<int> CountAsync(TId id) => await _dbSet.Where(e => e.Id!.Equals(id)).CountAsync(); public virtual async Task<int> CountAsync(TId id) => await _dbSet.Where(e => e.GetId().Equals(id)).CountAsync();
} }
} }

View File

@ -41,6 +41,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Infrastructure", "Infrastru
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DigitalData.Core.Exceptions", "DigitalData.Core.Exceptions\DigitalData.Core.Exceptions.csproj", "{BAEF6CC9-4FE2-4E3F-9D32-911C9E8CCFB4}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DigitalData.Core.Exceptions", "DigitalData.Core.Exceptions\DigitalData.Core.Exceptions.csproj", "{BAEF6CC9-4FE2-4E3F-9D32-911C9E8CCFB4}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DigitalData.Core.Exceptions.Middleware", "DigitalData.Core.Exceptions.Middleware\DigitalData.Core.Exceptions.Middleware.csproj", "{2336AE61-A21D-437E-A11B-367D008A64B2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exceptions", "Exceptions", "{8C3AF25D-81D9-4651-90CA-BF0BD2A03EA7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "assets", "assets", "{0A27EA70-74F4-48FB-881C-D741F2FCD456}"
ProjectSection(SolutionItems) = preProject
Assets\core_icon.png = Assets\core_icon.png
Assets\core_legacy_icon.png = Assets\core_legacy_icon.png
EndProjectSection
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -94,18 +104,22 @@ Global
{9BC2DEC5-E89D-48CC-9A51-4D94496EE4A6}.Debug|Any CPU.Build.0 = Debug|Any CPU {9BC2DEC5-E89D-48CC-9A51-4D94496EE4A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9BC2DEC5-E89D-48CC-9A51-4D94496EE4A6}.Release|Any CPU.ActiveCfg = Release|Any CPU {9BC2DEC5-E89D-48CC-9A51-4D94496EE4A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9BC2DEC5-E89D-48CC-9A51-4D94496EE4A6}.Release|Any CPU.Build.0 = Release|Any CPU {9BC2DEC5-E89D-48CC-9A51-4D94496EE4A6}.Release|Any CPU.Build.0 = Release|Any CPU
{C9266749-9504-4EA9-938F-F083357B60B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C9266749-9504-4EA9-938F-F083357B60B7}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{C9266749-9504-4EA9-938F-F083357B60B7}.Debug|Any CPU.Build.0 = Debug|Any CPU {C9266749-9504-4EA9-938F-F083357B60B7}.Debug|Any CPU.Build.0 = Release|Any CPU
{C9266749-9504-4EA9-938F-F083357B60B7}.Release|Any CPU.ActiveCfg = Release|Any CPU {C9266749-9504-4EA9-938F-F083357B60B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C9266749-9504-4EA9-938F-F083357B60B7}.Release|Any CPU.Build.0 = Release|Any CPU {C9266749-9504-4EA9-938F-F083357B60B7}.Release|Any CPU.Build.0 = Release|Any CPU
{CE00E1F7-2771-4D9C-88FB-E564894E539E}.Debug|Any CPU.ActiveCfg = Release|Any CPU {CE00E1F7-2771-4D9C-88FB-E564894E539E}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{CE00E1F7-2771-4D9C-88FB-E564894E539E}.Debug|Any CPU.Build.0 = Release|Any CPU {CE00E1F7-2771-4D9C-88FB-E564894E539E}.Debug|Any CPU.Build.0 = Release|Any CPU
{CE00E1F7-2771-4D9C-88FB-E564894E539E}.Release|Any CPU.ActiveCfg = Release|Any CPU {CE00E1F7-2771-4D9C-88FB-E564894E539E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CE00E1F7-2771-4D9C-88FB-E564894E539E}.Release|Any CPU.Build.0 = Release|Any CPU {CE00E1F7-2771-4D9C-88FB-E564894E539E}.Release|Any CPU.Build.0 = Release|Any CPU
{BAEF6CC9-4FE2-4E3F-9D32-911C9E8CCFB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BAEF6CC9-4FE2-4E3F-9D32-911C9E8CCFB4}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{BAEF6CC9-4FE2-4E3F-9D32-911C9E8CCFB4}.Debug|Any CPU.Build.0 = Debug|Any CPU {BAEF6CC9-4FE2-4E3F-9D32-911C9E8CCFB4}.Debug|Any CPU.Build.0 = Release|Any CPU
{BAEF6CC9-4FE2-4E3F-9D32-911C9E8CCFB4}.Release|Any CPU.ActiveCfg = Release|Any CPU {BAEF6CC9-4FE2-4E3F-9D32-911C9E8CCFB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BAEF6CC9-4FE2-4E3F-9D32-911C9E8CCFB4}.Release|Any CPU.Build.0 = Release|Any CPU {BAEF6CC9-4FE2-4E3F-9D32-911C9E8CCFB4}.Release|Any CPU.Build.0 = Release|Any CPU
{2336AE61-A21D-437E-A11B-367D008A64B2}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{2336AE61-A21D-437E-A11B-367D008A64B2}.Debug|Any CPU.Build.0 = Release|Any CPU
{2336AE61-A21D-437E-A11B-367D008A64B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2336AE61-A21D-437E-A11B-367D008A64B2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -127,7 +141,9 @@ Global
{C9266749-9504-4EA9-938F-F083357B60B7} = {72CBAFBA-55CC-49C9-A484-F8F4550054CB} {C9266749-9504-4EA9-938F-F083357B60B7} = {72CBAFBA-55CC-49C9-A484-F8F4550054CB}
{CE00E1F7-2771-4D9C-88FB-E564894E539E} = {41795B74-A757-4E93-B907-83BFF04EEE5C} {CE00E1F7-2771-4D9C-88FB-E564894E539E} = {41795B74-A757-4E93-B907-83BFF04EEE5C}
{41795B74-A757-4E93-B907-83BFF04EEE5C} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {41795B74-A757-4E93-B907-83BFF04EEE5C} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{BAEF6CC9-4FE2-4E3F-9D32-911C9E8CCFB4} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {BAEF6CC9-4FE2-4E3F-9D32-911C9E8CCFB4} = {8C3AF25D-81D9-4651-90CA-BF0BD2A03EA7}
{2336AE61-A21D-437E-A11B-367D008A64B2} = {8C3AF25D-81D9-4651-90CA-BF0BD2A03EA7}
{8C3AF25D-81D9-4651-90CA-BF0BD2A03EA7} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8E2C3187-F848-493A-9E79-56D20DDCAC94} SolutionGuid = {8E2C3187-F848-493A-9E79-56D20DDCAC94}