Skip to content

Commit

Permalink
Merge pull request #13 from ttkoma/next
Browse files Browse the repository at this point in the history
Next
  • Loading branch information
ttkoma authored Oct 28, 2021
2 parents a1a0967 + 0b0bca1 commit c573b70
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 82 deletions.
2 changes: 1 addition & 1 deletion CrmNx.Libs.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup Label="Auto Versioning">
<VersionNumber>1.0.22</VersionNumber>
<VersionNumber>1.0.23</VersionNumber>
<BuildDate>$([System.DateTime]::UtcNow.AddHours(3).ToString(`yyyyMMdd-HHmm`))</BuildDate>
<Version>$(VersionNumber)-$(BuildDate)</Version>
<VersionSuffix>rc</VersionSuffix>
Expand Down
10 changes: 6 additions & 4 deletions CrmNx.Xrm.Toolkit/Infrastructure/CrmWebApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public virtual async Task<Guid> CreateAsync(Entity entity)
}

var watch = Stopwatch.StartNew();
_logger.LogInformation("Starting {WebApiOperationName} {TargetEntity}", "CREATE", entity.LogicalName);
_logger.LogDebug("Starting {WebApiOperationName} {TargetEntity}", "CREATE", entity.LogicalName);

var collectionName = WebApiMetadata.GetEntitySetName(entity.LogicalName);
var json = JsonConvert.SerializeObject(entity, SerializerSettings);
Expand Down Expand Up @@ -135,7 +135,7 @@ public virtual async Task UpdateAsync(Entity entity, bool allowUpsert = false)
}

var watch = Stopwatch.StartNew();
_logger.LogInformation("Starting {WebApiOperationName} {TargetEntity}", "UPDATE", entity.LogicalName);
_logger.LogDebug("Starting {WebApiOperationName} {TargetEntity}", "UPDATE", entity.LogicalName);

var navLink = entity.ToNavigationLink(WebApiMetadata);

Expand Down Expand Up @@ -196,7 +196,7 @@ public virtual async Task DeleteAsync(EntityReference target)
}

var watch = Stopwatch.StartNew();
_logger.LogInformation("Starting {WebApiOperationName} {TargetEntity}", "DELETE", target.LogicalName);
_logger.LogDebug("Starting {WebApiOperationName} {TargetEntity}", "DELETE", target.LogicalName);


var requestId = Guid.NewGuid();
Expand Down Expand Up @@ -343,7 +343,9 @@ public virtual Task<EntityCollection> RetrieveMultipleAsync(string entityName,
[AllowNull] QueryOptions options = null,
CancellationToken cancellationToken = default)
{
_logger.LogInformation($"Start RetrieveMultipleAsync at {entityName}");
_logger.LogDebug("Starting {WebApiOperationName} at {TargetEntity}",
"RetrieveMultiple", entityName);

var requestId = Guid.NewGuid();

var queryString = (options ?? new QueryOptions())
Expand Down
102 changes: 62 additions & 40 deletions CrmNx.Xrm.Toolkit/Infrastructure/WebApiMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
Expand All @@ -20,8 +21,8 @@ public class WebApiMetadata : IWebApiMetadataService
private readonly IServiceProvider _serviceProvider;
private readonly ILogger<WebApiMetadata> _logger;

private readonly IList<KeyValuePair<string, string>> _dateOnlyAttributes =
new List<KeyValuePair<string, string>>();
private readonly ConcurrentDictionary<string, DateTimeBehavior> _dateAttributesBehavior =
new ConcurrentDictionary<string, DateTimeBehavior>();

public WebApiMetadata(IServiceProvider serviceProvider, ILogger<WebApiMetadata> logger) : this(logger)
{
Expand Down Expand Up @@ -65,26 +66,26 @@ public OneToManyRelationshipMetadata GetRelationshipMetadata(

public bool IsDateOnlyAttribute(string entityLogicalName, string attributeLogicalName)
{
if (_dateOnlyAttributes.Contains(
new KeyValuePair<string, string>(entityLogicalName, attributeLogicalName)))
var dateAttributeKey = $"{entityLogicalName}.{attributeLogicalName}"
.ToLowerInvariant();

if (_dateAttributesBehavior.ContainsKey(dateAttributeKey))
{
return true;
return _dateAttributesBehavior[dateAttributeKey] == DateTimeBehavior.DateOnly;
}

var isDateOnlyCheckResult = SearchDateOnlyAttributeAsync(entityLogicalName, attributeLogicalName)
var dateTimeAttributeBehavior = GetDateTimeBehaviorAttributeAsync(entityLogicalName, attributeLogicalName)
.GetAwaiter().GetResult();

if (isDateOnlyCheckResult)
{
_dateOnlyAttributes.Add(new KeyValuePair<string, string>(entityLogicalName, attributeLogicalName));
}
_dateAttributesBehavior.TryAdd(dateAttributeKey, dateTimeAttributeBehavior);

return isDateOnlyCheckResult;
return dateTimeAttributeBehavior == DateTimeBehavior.DateOnly;
}

protected virtual async Task<IEnumerable<EntityMetadata>> RetrieveEntityDefinitionsAsync()
{
_logger.LogDebug("Start RetrieveEntityDefinitionsAsync");
_logger.LogDebug("Starting {WebApiOperationName}","RetrieveEntityDefinitions");
var watch = Stopwatch.StartNew();

// TODO: FIXME - Direct build query with out extensions used WebApiMetadata for disable IoC loop!!!
// var queryString = $"{EntityMetadataPath}?$select={EntityMetadataFields}";
Expand All @@ -108,15 +109,18 @@ protected virtual async Task<IEnumerable<EntityMetadata>> RetrieveEntityDefiniti
.ExecuteAsync(request, cancellationToken: CancellationToken.None)
.ConfigureAwait(false);

_logger.LogDebug("Finish RetrieveEntityDefinitionsAsync");
watch.Stop();
_logger.LogInformation("Complete {WebApiOperationName} in {Elapsed:0.0} ms",
"RetrieveEntityDefinitions", watch.Elapsed.TotalMilliseconds);

return collection?.Items;
}

protected virtual async Task<IEnumerable<OneToManyRelationshipMetadata>> RetrieveOneToManyRelationshipsAsync()
{
_logger.LogInformation("Start RetrieveOneToManyRelationshipsAsync");

_logger.LogDebug("Starting {WebApiOperationName}", "RetrieveOneToManyRelationships");
var watch = Stopwatch.StartNew();

// TODO: FIXME - Direct build query with out extensions used WebApiMetadata for disable IoC loop!!!
// var query = $"{OneToManyRelationShipPath}?$select={OneToManyRelationshipFields}";
var request =
Expand All @@ -139,17 +143,22 @@ protected virtual async Task<IEnumerable<OneToManyRelationshipMetadata>> Retriev
var collection = await GetCrmClient()
.ExecuteAsync(request, CancellationToken.None)
.ConfigureAwait(false);

_logger.LogInformation("Finish RetrieveOneToManyRelationshipsAsync");

_logger.LogInformation("Complete {WebApiOperationName} in {Elapsed:0.0} ms",
"RetrieveOneToManyRelationships", watch.Elapsed.TotalMilliseconds);

return collection?.Items;
}

protected virtual async Task<bool> SearchDateOnlyAttributeAsync(string entityLogicalName, string attributeLogicalName)
protected virtual async Task<DateTimeBehavior> GetDateTimeBehaviorAttributeAsync(string entityLogicalName,
string attributeLogicalName)
{
_logger.LogInformation("Start CheckAttributeIsDateOnly {Entity}.{Attribute}", entityLogicalName, attributeLogicalName);
var watch = new Stopwatch();
watch.Start();
_logger.LogDebug("Starting {WebApiOperationName} {Entity}.{Attribute}",
"GetDateTimeBehavior",
entityLogicalName,
attributeLogicalName);

var watch = Stopwatch.StartNew();

// TODO: FIXME - Direct build query with out extensions used WebApiMetadata for disable IoC loop!!!
//var query = string.Format(CultureInfo.InvariantCulture, CheckAttributeDateOnlyRequest, entityLogicalName,
Expand All @@ -162,41 +171,54 @@ protected virtual async Task<bool> SearchDateOnlyAttributeAsync(string entityLog

Parameters =
{
{"$select", "LogicalName,Format,DateTimeBehavior"},
{
"$filter",
"DateTimeBehavior ne null and Format eq Microsoft.Dynamics.CRM.DateTimeFormat'DateOnly'"
}
// {"$select", "LogicalName,Format,DateTimeBehavior"},
{ "$select", "LogicalName,Format,DateTimeBehavior" },
// {
// "$filter",
// "DateTimeBehavior ne null and Format eq Microsoft.Dynamics.CRM.DateTimeFormat'DateOnly'"
// }
}
};

bool isDateOnly = false;
DateTimeBehavior behavior = default;

try
{
var result = await GetCrmClient().ExecuteAsync(request, CancellationToken.None)
var result = await GetCrmClient()
.ExecuteAsync(request, CancellationToken.None)
.ConfigureAwait(false);

isDateOnly = result["DateTimeBehavior"]?["Value"]?.ToString() == "DateOnly";
}
catch (WebApiException ex)
{
if (Equals(ex.StatusCode, HttpStatusCode.NotFound))
var stringValue = result["DateTimeBehavior"]?["Value"]?.ToString();
if (Enum.TryParse(typeof(DateTimeBehavior), stringValue, true, out var parsedValue))
{
isDateOnly = false;
}
else
{
throw;
behavior = (DateTimeBehavior)parsedValue;
}
}
catch (Exception ex)
{
throw;
}
// catch (WebApiException ex)
// {
// // if (Equals(ex.StatusCode, HttpStatusCode.NotFound))
// // {
// // isDateOnly = false;
// // }
// // else
// // {
// // throw;
// // }
// }
finally
{
watch.Stop();
_logger.LogInformation("Finish CheckAttributeIsDateOnly {EntityName}.{AttributeName} - {IsDateOnly} in {Elapsed:0.0} ms", entityLogicalName, attributeLogicalName, isDateOnly, watch.Elapsed.TotalMilliseconds);
_logger.LogInformation(
"Complete {WebApiOperationName} {EntityName}.{AttributeName} - {DateTimeBehavior} in {Elapsed:0.0} ms",
"GetDateTimeBehavior",
entityLogicalName, attributeLogicalName, behavior, watch.Elapsed.TotalMilliseconds);
}

return isDateOnly;
return behavior;
}

private void SetEntityDefinitions(IEnumerable<EntityMetadata> entityMetadataCollection)
Expand Down
9 changes: 9 additions & 0 deletions CrmNx.Xrm.Toolkit/Metadata/DateTimeBehavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace CrmNx.Xrm.Toolkit.Metadata
{
public enum DateTimeBehavior
{
UserLocal = 1,
DateOnly = 2,
TimeZoneIndependent = 3
}
}
20 changes: 16 additions & 4 deletions Tests/CrmNx.Crm.Toolkit.Testing/MockedWebApiMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ public class MockedWebApiMetadata : WebApiMetadata, IWebApiMetadataService
new KeyValuePair<string, string>("contact", "birthdate22")
};

private static readonly IList<KeyValuePair<string, string>> DateTimeZoneIndependentAttributes =
new List<KeyValuePair<string, string>>
{
};

/// <summary>
/// Create Service Contains Metadata definitions for Dynamics Testing Environment
/// </summary>
Expand Down Expand Up @@ -61,12 +66,19 @@ protected override Task<IEnumerable<OneToManyRelationshipMetadata>> RetrieveOneT
return Task.FromResult(LoadOneToManyRelationships);
}

protected override Task<bool> SearchDateOnlyAttributeAsync(string entityLogicalName, string attributeLogicalName)
protected override Task<DateTimeBehavior> GetDateTimeBehaviorAttributeAsync(string entityLogicalName,
string attributeLogicalName)
{
var isDateOnly = DateOnlyAttributes.Contains(
new KeyValuePair<string, string>(entityLogicalName, attributeLogicalName));
if (DateOnlyAttributes.Contains(
new KeyValuePair<string, string>(entityLogicalName, attributeLogicalName)))
return Task.FromResult(DateTimeBehavior.DateOnly);

if (DateTimeZoneIndependentAttributes.Contains(
new KeyValuePair<string, string>(entityLogicalName, attributeLogicalName)
))
return Task.FromResult(DateTimeBehavior.TimeZoneIndependent);

return Task.FromResult(isDateOnly);
return Task.FromResult(DateTimeBehavior.UserLocal);
}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
using System;
using System.Collections.Generic;
using System.Text;
using CrmNx.Xrm.Toolkit;

namespace CrmNx.Xrm.Toolkit.UnitTests
namespace CrmNx.Crm.Toolkit.Testing.ProxyClasses
{
internal class Account : Entity
public class Account : Entity
{
public const string EntityLogicalName = "account";
public const string PrimaryIdAttributeName = "accountid";
Expand All @@ -21,6 +20,8 @@ public Account(Guid accountId) : this()
Id = accountId;
}

public static EntityReference Reference(Guid id) => new EntityReference(EntityLogicalName, id);


public Account(int accountNumber) : base(EntityLogicalName, PropertyNames.AccountNumber, accountNumber)
{
Expand All @@ -47,6 +48,12 @@ public int AccountNumber
get => GetAttributeValue<int>(PropertyNames.AccountNumber);
set => SetAttributeValue(PropertyNames.AccountNumber, value);
}

public EntityReference PrimaryContactId
{
get => GetAttributeValue<EntityReference>(PropertyNames.PrimaryContactId);
set => SetAttributeValue(PropertyNames.PrimaryContactId, value);
}

public StateCodeEnum StateCode
{
Expand All @@ -68,6 +75,7 @@ public static class PropertyNames

public const string StateCode = "statecode";
public const string AccountNumber = "accountnumber";
public const string PrimaryContactId = "primarycontactid";
}
}
}
Loading

0 comments on commit c573b70

Please sign in to comment.