Compare commits
32 Commits
f7193594b1
...
816d5835f1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
816d5835f1 | ||
|
|
4a64a31d47 | ||
|
|
e9b2ba788f | ||
|
|
e53813500a | ||
|
|
25e3855de2 | ||
|
|
dd3d6e70cc | ||
|
|
02a87309df | ||
|
|
0f7bdc9d0e | ||
|
|
f9df2fb29e | ||
|
|
ef7da0e52c | ||
|
|
f602a842be | ||
|
|
52a7664e57 | ||
|
|
ea3d1312b8 | ||
|
|
3b8b315fea | ||
|
|
c65eefb954 | ||
|
|
997fd533ac | ||
|
|
bcfb5a8a70 | ||
|
|
049e9977f4 | ||
|
|
0334fc4cdf | ||
|
|
0c2334cefb | ||
|
|
dd7f1c1ea0 | ||
|
|
4bb242a4cc | ||
|
|
b577067379 | ||
|
|
bd4d4856ea | ||
|
|
c3a12ba5b7 | ||
|
|
478bf13a4a | ||
|
|
d8849f48da | ||
|
|
c466c553dc | ||
|
|
48afa6b433 | ||
|
|
e44b2895c9 | ||
|
|
85e5fc4018 | ||
|
|
70ccec9fef |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -409,3 +409,4 @@ FodyWeavers.xsd
|
||||
/DigitalData.Core.ConsoleApp/Program.cs
|
||||
/DigitalData.Core.ConsoleApp/FooHttpOptions.cs
|
||||
/DigitalData.Core.Tests/obj/
|
||||
/DigitalData.Core.Terminal
|
||||
|
||||
@@ -4,15 +4,17 @@ namespace DigitalData.Core.Abstractions.Client
|
||||
{
|
||||
public interface IBaseHttpClientService
|
||||
{
|
||||
public string Uri { get; init; }
|
||||
|
||||
public CookieCollection GetCookies(string route = "");
|
||||
CookieCollection GetCookies(string path = "");
|
||||
|
||||
Task<HttpResponseMessage> FetchAsync(
|
||||
string route = "",
|
||||
string? scheme = null,
|
||||
int? port = null,
|
||||
string path = "",
|
||||
IEnumerable<KeyValuePair<string, object?>>? queryParams = null,
|
||||
HttpMethod? method = null,
|
||||
HttpContent? body = null,
|
||||
Dictionary<string, string>? form = null,
|
||||
IEnumerable<KeyValuePair<string, object>>? form = null,
|
||||
IEnumerable<KeyValuePair<string, object>>? headers = null,
|
||||
bool sendWithCookie = true,
|
||||
bool saveCookie = true
|
||||
);
|
||||
|
||||
13
DigitalData.Core.Abstractions/Client/IHttpClientOptions.cs
Normal file
13
DigitalData.Core.Abstractions/Client/IHttpClientOptions.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace DigitalData.Core.Abstractions.Client
|
||||
{
|
||||
public interface IHttpClientOptions
|
||||
{
|
||||
string Uri { get; init; }
|
||||
|
||||
string? Path { get; init; }
|
||||
|
||||
Dictionary<string, object>? Headers { get; init; }
|
||||
|
||||
Dictionary<string, object?>? QueryParams { get; init; }
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace DigitalData.Core.Abstractions.Client
|
||||
{
|
||||
public interface IHttpClientService<TClientOptions> : IBaseHttpClientService
|
||||
public interface IHttpClientService<TClientOptions> : IBaseHttpClientService where TClientOptions : IHttpClientOptions
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,10 @@
|
||||
<PackageProjectUrl></PackageProjectUrl>
|
||||
<RepositoryUrl>http://git.dd:3000/AppStd/WebCoreModules.git</RepositoryUrl>
|
||||
<PackAsTool>False</PackAsTool>
|
||||
<NeutralLanguage>aa-DJ</NeutralLanguage>
|
||||
<PackageIcon>core_icon.png</PackageIcon>
|
||||
<Version>2.0.0.0</Version>
|
||||
<Version>2.2.1</Version>
|
||||
<AssemblyVersion>2.2.1</AssemblyVersion>
|
||||
<FileVersion>2.2.1</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
public interface IRSADecryptor : IRSACryptographer
|
||||
{
|
||||
(string Value, Version Version) VersionedPassword { init; }
|
||||
(string Value, Version Version)? VersionedPassword { init; }
|
||||
|
||||
Version? PasswordVersion { get; }
|
||||
|
||||
|
||||
@@ -1,44 +1,113 @@
|
||||
using DigitalData.Core.Abstractions.Client;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net;
|
||||
using System.Web;
|
||||
|
||||
namespace DigitalData.Core.Client
|
||||
{
|
||||
public class BaseHttpClientService : IBaseHttpClientService
|
||||
{
|
||||
protected readonly HttpClient _client;
|
||||
protected readonly CookieContainer _cookies;
|
||||
protected readonly CookieContainer _cookies;
|
||||
|
||||
[StringSyntax("Uri")]
|
||||
public string Uri { get; init; }
|
||||
protected readonly string _uri;
|
||||
|
||||
public BaseHttpClientService(HttpClient client, CookieContainer cookieContainer, IOptions<HttpClientOptions> clientOptions)
|
||||
protected readonly string _path;
|
||||
|
||||
protected IEnumerable<KeyValuePair<string, object>>? _headers;
|
||||
|
||||
protected IEnumerable<KeyValuePair<string, object?>>? _queryParams;
|
||||
|
||||
internal BaseHttpClientService(HttpClient client, CookieContainer cookieContainer, IHttpClientOptions clientOptions)
|
||||
{
|
||||
_client = client;
|
||||
_cookies = cookieContainer;
|
||||
Uri = clientOptions.Value.Uri;
|
||||
_uri = clientOptions.Uri.Trim(URI_TRIM_CHARS);
|
||||
_path = clientOptions.Path?.Trim(URI_TRIM_CHARS) ?? string.Empty;
|
||||
_headers = clientOptions.Headers;
|
||||
_queryParams = clientOptions.QueryParams;
|
||||
}
|
||||
|
||||
public CookieCollection GetCookies(string route = "") => _cookies.GetCookies(uri: new Uri(Uri + route));
|
||||
public CookieCollection GetCookies(string path = "") => _cookies.GetCookies(uri: new Uri(UriCombine(_uri, path, path.Trim(URI_TRIM_CHARS))));
|
||||
|
||||
public async Task<HttpResponseMessage> FetchAsync(
|
||||
string route = "",
|
||||
string? scheme = null,
|
||||
int? port = null,
|
||||
string path = "",
|
||||
IEnumerable<KeyValuePair<string, object?>>? queryParams = null,
|
||||
HttpMethod? method = null,
|
||||
HttpContent? body = null,
|
||||
Dictionary<string, string>? form = null,
|
||||
IEnumerable<KeyValuePair<string, object>>? form = null,
|
||||
IEnumerable<KeyValuePair<string, object>>? headers = null,
|
||||
bool sendWithCookie = true,
|
||||
bool saveCookie = true
|
||||
)
|
||||
{
|
||||
// merge with default headers
|
||||
if(_headers is not null)
|
||||
{
|
||||
if (headers is null)
|
||||
headers = _headers;
|
||||
else
|
||||
{
|
||||
var mergedHeaders = headers.ToList();
|
||||
mergedHeaders.AddRange(_headers);
|
||||
headers = mergedHeaders;
|
||||
}
|
||||
}
|
||||
|
||||
// Add default query parameters
|
||||
if(_queryParams is not null)
|
||||
{
|
||||
if (queryParams is null)
|
||||
queryParams = _queryParams;
|
||||
else
|
||||
{
|
||||
var mergedQueryParams = queryParams.ToList();
|
||||
mergedQueryParams.AddRange(_queryParams);
|
||||
queryParams = mergedQueryParams;
|
||||
}
|
||||
}
|
||||
|
||||
// set default HTTP method as GET
|
||||
method ??= HttpMethod.Get;
|
||||
|
||||
// create URL
|
||||
var requestUriStr = Uri + route;
|
||||
var requestUri = new Uri(requestUriStr);
|
||||
var uriBuilder = new UriBuilder(_uri);
|
||||
if (scheme is not null)
|
||||
uriBuilder.Scheme = scheme;
|
||||
if (port is int portInt)
|
||||
uriBuilder.Port = portInt;
|
||||
uriBuilder.Path = UriCombine(_path, path?.Trim(URI_TRIM_CHARS) ?? string.Empty);
|
||||
|
||||
var requestMessage = new HttpRequestMessage(method, requestUriStr);
|
||||
// Add query parameters if provided
|
||||
if (queryParams?.Any() ?? false)
|
||||
{
|
||||
var query = HttpUtility.ParseQueryString(uriBuilder.Query);
|
||||
|
||||
var flagParams = queryParams.Where(param => param.Value is null).Select(param => param.Key);
|
||||
|
||||
var valueParams = queryParams.Where(param => param.Value is not null);
|
||||
|
||||
foreach (var param in valueParams)
|
||||
query[param.Key] = param.Value switch
|
||||
{
|
||||
bool b => b.ToString().ToLower(),
|
||||
_ => param.Value.ToString()
|
||||
};
|
||||
|
||||
if (flagParams.Any())
|
||||
uriBuilder.Query = string.Join(QUERY_SEPARATOR, query.ToString(), string.Join(QUERY_SEPARATOR, flagParams));
|
||||
else uriBuilder.Query = query.ToString();
|
||||
}
|
||||
|
||||
var requestUri = uriBuilder.Uri;
|
||||
|
||||
var requestMessage = new HttpRequestMessage(method, requestUri);
|
||||
|
||||
// Add headers if provided
|
||||
headers?.ForEach(header => requestMessage.Headers.Add(header.Key, header.Value.ToString()));
|
||||
|
||||
// Add cookie to request
|
||||
if (sendWithCookie)
|
||||
@@ -56,7 +125,7 @@ namespace DigitalData.Core.Client
|
||||
else if (body != null)
|
||||
requestMessage.Content = body;
|
||||
else if (form != null)
|
||||
requestMessage.Content = new FormUrlEncodedContent(form);
|
||||
requestMessage.Content = new FormUrlEncodedContent(form.Select(e => KeyValuePair.Create(e.Key, e.Value.ToString())));
|
||||
|
||||
var response = await _client.SendAsync(requestMessage);
|
||||
|
||||
@@ -68,5 +137,11 @@ namespace DigitalData.Core.Client
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
internal static readonly char[] URI_TRIM_CHARS = { '\\', '/', ' ' };
|
||||
|
||||
internal static string UriCombine(params string[] paths) => System.IO.Path.Combine(paths).Replace("\\", "/");
|
||||
|
||||
internal static readonly char QUERY_SEPARATOR = '&';
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,35 @@
|
||||
using DigitalData.Core.Abstractions.Client;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Net;
|
||||
|
||||
namespace DigitalData.Core.Client
|
||||
{
|
||||
public static class DIExtensions
|
||||
{
|
||||
public static IServiceCollection AddHttpClientService(this IServiceCollection services, string uri)
|
||||
internal static IServiceCollection AddHttpClientServiceDefaults(this IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<HttpClient>();
|
||||
services.TryAddSingleton<CookieContainer>();
|
||||
services.AddSingleton<IBaseHttpClientService, BaseHttpClientService>();
|
||||
services.Configure<HttpClientOptions>(opt => opt.Uri = uri);
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddHttpClientService<TClientOptions>(this IServiceCollection services, Action<TClientOptions>? clientOptions = null, bool setAsDefaultBase = false)
|
||||
where TClientOptions : HttpClientOptions
|
||||
public static IServiceCollection AddHttpClientService<THttpClientOptions>(this IServiceCollection services, IConfigurationSection section)
|
||||
where THttpClientOptions : class, IHttpClientOptions
|
||||
{
|
||||
services.TryAddSingleton<HttpClient>();
|
||||
services.TryAddSingleton<CookieContainer>();
|
||||
services.AddSingleton<IHttpClientService<TClientOptions>, HttpClientService<TClientOptions>>();
|
||||
services.Configure(clientOptions ?? (_ => { }));
|
||||
|
||||
if (setAsDefaultBase)
|
||||
services.AddSingleton<IBaseHttpClientService, HttpClientService<TClientOptions>>();
|
||||
services.AddHttpClientServiceDefaults();
|
||||
services.TryAddSingleton<IHttpClientService<THttpClientOptions>, HttpClientService<THttpClientOptions>>();
|
||||
return services.Configure<THttpClientOptions>(section);
|
||||
}
|
||||
|
||||
public static IServiceCollection AddHttpClientService<THttpClientOptions>(this IServiceCollection services, THttpClientOptions options)
|
||||
where THttpClientOptions : class, IHttpClientOptions
|
||||
{
|
||||
services.AddHttpClientServiceDefaults();
|
||||
services.TryAddSingleton<IHttpClientService<THttpClientOptions>, HttpClientService<THttpClientOptions>>();
|
||||
services.TryAddSingleton(Options.Create(options));
|
||||
return services;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
|
||||
@@ -6,7 +6,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<Description>This package provides HTTP client extension methods for the DigitalData.Core library, offering simplified and asynchronous methods for fetching and handling HTTP responses. It includes utility methods for sending GET requests, reading response content as text or JSON, and deserializing JSON into dynamic or strongly-typed objects using Newtonsoft.Json. These extensions facilitate efficient and easy-to-read HTTP interactions in client applications.</Description>
|
||||
<PackageId>DigitalData.Core.Client</PackageId>
|
||||
<Version>1.0.1.1</Version>
|
||||
<Version>2.0.3</Version>
|
||||
<Authors>Digital Data GmbH</Authors>
|
||||
<Company>Digital Data GmbH</Company>
|
||||
<Product>Digital Data GmbH</Product>
|
||||
@@ -15,6 +15,8 @@
|
||||
<PackageIcon>core_icon.png</PackageIcon>
|
||||
<RepositoryUrl>http://git.dd:3000/AppStd/WebCoreModules.git</RepositoryUrl>
|
||||
<PackageTags>digital data core http client json serilization</PackageTags>
|
||||
<AssemblyVersion>2.0.3</AssemblyVersion>
|
||||
<FileVersion>2.0.3</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -27,6 +29,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="7.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace DigitalData.Core.Client
|
||||
{
|
||||
public class HttpClientOptions
|
||||
{
|
||||
public string Uri { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,9 @@ using System.Net;
|
||||
namespace DigitalData.Core.Client
|
||||
{
|
||||
public class HttpClientService<TClientOptions> : BaseHttpClientService, IHttpClientService<TClientOptions>, IBaseHttpClientService
|
||||
where TClientOptions : HttpClientOptions
|
||||
where TClientOptions : class, IHttpClientOptions
|
||||
{
|
||||
public HttpClientService(HttpClient client, CookieContainer cookieContainer, IOptions<TClientOptions> clientOptions) : base(client, cookieContainer, clientOptions)
|
||||
public HttpClientService(HttpClient client, CookieContainer cookieContainer, IOptions<TClientOptions> clientOptions) : base(client, cookieContainer, clientOptions.Value)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace DigitalData.Core.Client
|
||||
|
||||
public static T Provide<T>() where T : notnull => _lazyProvider.Value.GetRequiredService<T>();
|
||||
|
||||
public static IHttpClientService<TOptions> ProvideHttpClientService<TOptions>() where TOptions : notnull
|
||||
public static IHttpClientService<TOptions> ProvideHttpClientService<TOptions>() where TOptions : IHttpClientOptions
|
||||
=> _lazyProvider.Value.GetRequiredService<IHttpClientService<TOptions>>();
|
||||
}
|
||||
}
|
||||
@@ -6,12 +6,12 @@ namespace DigitalData.Core.Security
|
||||
{
|
||||
public class RSADecryptor : RSACryptographer, IRSADecryptor, IRSACryptographer
|
||||
{
|
||||
public (string Value, Version Version) VersionedPassword
|
||||
public (string Value, Version Version)? VersionedPassword
|
||||
{
|
||||
init
|
||||
{
|
||||
_password = value.Value;
|
||||
PasswordVersion = value.Version;
|
||||
_password = value?.Value;
|
||||
PasswordVersion = value?.Version;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Security.Cryptography;
|
||||
using DigitalData.Core.Abstractions.Security;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace DigitalData.Core.Security
|
||||
@@ -106,5 +107,26 @@ namespace DigitalData.Core.Security
|
||||
|
||||
return new string(pemChars);
|
||||
}
|
||||
|
||||
public async Task<IRSADecryptor> ReadRSADecryptorAsync(string path, Version? version = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var pem = await File.ReadAllTextAsync(path, cancellationToken);
|
||||
|
||||
(string Value, Version Version)? versionedPassword = null;
|
||||
|
||||
if(version is not null)
|
||||
{
|
||||
if (version != Secrets.Version)
|
||||
throw new InvalidOperationException($"The provided version {version} does not match the expected version {Secrets.Version}.");
|
||||
|
||||
versionedPassword = (Secrets.PBE_PASSWORD, Secrets.Version);
|
||||
}
|
||||
|
||||
return new RSADecryptor()
|
||||
{
|
||||
Pem = pem,
|
||||
VersionedPassword = versionedPassword
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,22 +14,46 @@ namespace DigitalData.Core.Tests.Client
|
||||
public void SetUp()
|
||||
{
|
||||
_serviceProvider = new ServiceCollection()
|
||||
.AddHttpClientService("https://jsonplaceholder.typicode.com/todos")
|
||||
.AddHttpClientService("https://jsonplaceholder.typicode.com", "todos")
|
||||
.BuildServiceProvider();
|
||||
|
||||
_service = _serviceProvider.GetRequiredService<IBaseHttpClientService>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task FetchJsonAsync_ShouldReturnJsonResponse()
|
||||
public async Task FetchJsonAsync_ShouldReturnJsonResponse_WithCorrectWithPath()
|
||||
{
|
||||
// Act
|
||||
var expectedUserId = (int) await _service.FetchAsync("/1", sendWithCookie: false, saveCookie: false)
|
||||
var expectedUserId = (int) await _service.FetchAsync(path: "/1", sendWithCookie: false, saveCookie: false)
|
||||
.ThenAsync(res => res.Json())
|
||||
.ThenAsync(todo => todo.userId);
|
||||
|
||||
// Assert
|
||||
Assert.That(expectedUserId, Is.EqualTo(1), "The userId of the fetched JSON object should be 1.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task FetchJsonAsync_ShouldReturnJsonResponse_WithQueryParams()
|
||||
{
|
||||
var queryParams = new Dictionary<string, object?>
|
||||
{
|
||||
{ "id", "1" }
|
||||
};
|
||||
|
||||
// Act
|
||||
var dyn_id = await _service.FetchAsync(queryParams: queryParams, sendWithCookie: false, saveCookie: false)
|
||||
.ThenAsync(res => res.JsonList())
|
||||
.ThenAsync(todo => todo.FirstOrDefault()?.userId);
|
||||
|
||||
try
|
||||
{
|
||||
Assert.That((int)dyn_id, Is.EqualTo(1), "The userId of the fetched JSON object should be 1.");
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
// Handle the case where the cast is not possible
|
||||
Assert.Fail("The id could not be cast to an integer.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DigitalData.Core.Legacy.Cli
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DigitalData.Core.Security", "DigitalData.Core.Security\DigitalData.Core.Security.csproj", "{47D80C65-74A2-4EB8-96A5-D571A9108FB3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DigitalData.Core.Security.Extensions", "DigitalData.Core.Security.Extensions\DigitalData.Core.Security.Extensions.csproj", "{D740182D-82DA-480A-9F87-BFB4A8620A00}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DigitalData.Core.Security.Extensions", "DigitalData.Core.Security.Extensions\DigitalData.Core.Security.Extensions.csproj", "{D740182D-82DA-480A-9F87-BFB4A8620A00}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DigitalData.Core.Terminal", "DigitalData.Core.Terminal\DigitalData.Core.Terminal.csproj", "{0FA93730-8084-4907-B172-87D610323796}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -51,8 +53,8 @@ Global
|
||||
{0B051A5F-BD38-47D1-BAFF-D44BA30D3FB7}.Debug|Any CPU.Build.0 = Release|Any CPU
|
||||
{0B051A5F-BD38-47D1-BAFF-D44BA30D3FB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0B051A5F-BD38-47D1-BAFF-D44BA30D3FB7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6A80FFEC-9B83-40A7-8C78-124440B48B33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6A80FFEC-9B83-40A7-8C78-124440B48B33}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6A80FFEC-9B83-40A7-8C78-124440B48B33}.Debug|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6A80FFEC-9B83-40A7-8C78-124440B48B33}.Debug|Any CPU.Build.0 = Release|Any CPU
|
||||
{6A80FFEC-9B83-40A7-8C78-124440B48B33}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6A80FFEC-9B83-40A7-8C78-124440B48B33}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{13E40DF1-6123-4838-9BF8-086C94E6ADF6}.Debug|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -74,6 +76,10 @@ Global
|
||||
{D740182D-82DA-480A-9F87-BFB4A8620A00}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D740182D-82DA-480A-9F87-BFB4A8620A00}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D740182D-82DA-480A-9F87-BFB4A8620A00}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0FA93730-8084-4907-B172-87D610323796}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0FA93730-8084-4907-B172-87D610323796}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0FA93730-8084-4907-B172-87D610323796}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0FA93730-8084-4907-B172-87D610323796}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
Reference in New Issue
Block a user