Constraint Reference 'ApiVersion' counld not resolved to a type - api-versioning

Constraint Reference Exception
Hi,
I'm using .Net 6 Web API with versioning, my versioning works just fine in Swagger, but when I reference my API from MVC Framework (.NET 6), I'm getting an exception that says :
InvalidOperationException: The constraint reference 'apiVersion' could not be resolved to a type. Register the constraint type with 'Microsoft.AspNetCore.Routing.RouteOptions.ConstraintMap'.
public static IServiceCollection AddApiVersioningConfig(this IServiceCollection services)
{
services.AddApiVersioning(cfg =>
{
cfg.DefaultApiVersion = new ApiVersion(1, 0);
cfg.AssumeDefaultVersionWhenUnspecified = true; // In case if the user doesn't specify the version, so we assume to use the default one (v1)
cfg.ReportApiVersions = true; // This will mention which API the user is currently using (Header).
// 1- api/v1/clients/ => In order to read the segment that contains the version eg.
// 2- api-version : 1.0 => In case the user provides the version as header
// 3- ?api-version=1.0 => From query approach
cfg.ApiVersionReader = ApiVersionReader.Combine(
new HeaderApiVersionReader("X-version"),
new QueryStringApiVersionReader("api-version"),
new UrlSegmentApiVersionReader(),
new MediaTypeApiVersionReader("ver"));
});
return services;
}
}
app.UseSwaggerUI(opt =>
{
var provider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>();
foreach (var description in provider.ApiVersionDescriptions)
{
opt.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.ApiVersion.ToString());
}
});
Many thanks for your help :)
KingKali

Related

How to simulate a CRM plugin sandbox isolation mode in unit tests?

Context
I would like to write some unit tests against classes what will be utilized by CRM 2016 CodeActivity and Plugin classes. The final assembly will be registered in sandbox isolation mode.
I want to be sure if a test case is green when running unit tests, it will not be more restricted in sandbox isolation security restrictions when registered and run in CRM.
Question
Is there any way to simulate the sandbox isolation when running unit tests?
That's a really good question. You can maybe simulate running the plugin assemblies and code activities in a sandbox based on this Sandbox example.
With that example you could run the codeactivity with a limited set of permissions.
Now, what are the exact limitations of CRM online? Found this article. There is a Sandbox Limitations sections with some of them. If you find another one please let me know. Cause I'd be keen on adding this feature to FakeXrmEasy
Cheers,
I found this today: https://github.com/carltoncolter/DynamicsPlugin/blob/master/DynamicsPlugin.Tests/PluginContainer.cs
Which I used to turn into this:
using System;
using System.Diagnostics;
using System.Globalization;
using System.Net;
using System.Net.NetworkInformation;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;
namespace Core.DLaB.Xrm.Tests.Sandbox
{
public static class SandboxWrapper
{
public static T Instantiate<T>(object[] constructorArguments = null)
{
return new SandboxWrapper<T>().Instantiate(constructorArguments);
}
public static T InstantiatePlugin<T>(string unsecureConfig = null, string secureConfig = null)
{
object[] args = null;
if (secureConfig == null)
{
if (unsecureConfig != null)
{
args = new object[] {unsecureConfig};
}
}
else
{
args = new object[]{unsecureConfig, secureConfig};
}
return new SandboxWrapper<T>().Instantiate(args);
}
}
public class SandboxWrapper<T> : MarshalByRefObject, IDisposable
{
private const string DomainSuffix = "Sandbox";
/// <summary>
/// The Sandbox AppDomain to execute the plugin
/// </summary>
public AppDomain SandboxedAppDomain { get; private set; }
public T Instantiate(object[] constructorArguments = null)
{
/*
* Sandboxed plug-ins and custom workflow activities can access the network through the HTTP and HTTPS protocols. This capability provides
support for accessing popular web resources like social sites, news feeds, web services, and more. The following web access restrictions
apply to this sandbox capability.
* Only the HTTP and HTTPS protocols are allowed.
* Access to localhost (loopback) is not permitted.
* IP addresses cannot be used. You must use a named web address that requires DNS name resolution.
* Anonymous authentication is supported and recommended. There is no provision for prompting the
on user for credentials or saving those credentials.
*/
constructorArguments = constructorArguments ?? new object[] { };
var type = typeof(T);
var source = type.Assembly.Location;
var sourceAssembly = Assembly.UnsafeLoadFrom(source);
var setup = new AppDomainSetup
{
ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
ApplicationName = $"{sourceAssembly.GetName().Name}{DomainSuffix}",
DisallowBindingRedirects = true,
DisallowCodeDownload = true,
DisallowPublisherPolicy = true
};
var ps = new PermissionSet(PermissionState.None);
ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.SerializationFormatter));
ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
ps.AddPermission(new FileIOPermission(PermissionState.None));
ps.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess));
//RegEx pattern taken from: https://msdn.microsoft.com/en-us/library/gg334752.aspx
ps.AddPermission(new WebPermission(NetworkAccess.Connect,
new Regex(
#"^http[s]?://(?!((localhost[:/])|(\[.*\])|([0-9]+[:/])|(0x[0-9a-f]+[:/])|(((([0-9]+)|(0x[0-9A-F]+))\.){3}(([0-9]+)|(0x[0-9A-F]+))[:/]))).+")));
// We don't need to add these, but it is important to note that there is no access to the following
ps.AddPermission(new NetworkInformationPermission(NetworkInformationAccess.None));
ps.AddPermission(new EnvironmentPermission(PermissionState.None));
ps.AddPermission(new RegistryPermission(PermissionState.None));
ps.AddPermission(new EventLogPermission(PermissionState.None));
SandboxedAppDomain = AppDomain.CreateDomain(DomainSuffix, null, setup, ps, null);
return Create(constructorArguments);
}
private T Create(object[] constructorArguments)
{
var type = typeof(T);
return (T)Activator.CreateInstanceFrom(
SandboxedAppDomain,
type.Assembly.ManifestModule.FullyQualifiedName,
// ReSharper disable once AssignNullToNotNullAttribute
type.FullName, false, BindingFlags.CreateInstance,
null, constructorArguments,
CultureInfo.CurrentCulture, null
).Unwrap();
}
#region IDisposable Support
//Implementing IDisposable Pattern: https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/dispose-pattern
private bool _disposed; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (_disposed) return;
if (disposing)
{
if (SandboxedAppDomain != null)
{
AppDomain.Unload(SandboxedAppDomain);
SandboxedAppDomain = null;
}
}
_disposed = true;
}
// This code added to correctly implement the disposable pattern.
void IDisposable.Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
}
#endregion
}
}
Which can be used as such:
SandboxWrapper.InstantiatePlugin<YourPluginType>(unsecureString, secureString)
Not sure how much of it is valid or not, but it worked for handling my testing of xml and JSON serialization correctly.

MS CRM 2013 Attribute parentcustomeridtype must not be NULL if attribute parentcustomerid is not NULL

Dear smart developers out there,
I encounter a problem when I want to create a contact belonging to an organization in Microsoft Dynamics CRM 2013 via web services
client = new OrganizationServiceClient("CustomBinding_IOrganizationService");
var newContactProperties = new Dictionary<string, object> {
{ "lastname", "TestContact"},
{ "firstname", "A"},
{ "fullname", "A TestContact"}
};
/* organizationType is a CRM.CRMWebServices.OptionSetValue
* with ExtensionData null, PropertyChanged null and a valid Value
*
* orgReference is a CRM.CRMWebServices.EntityReference
* with a valid Id
*/
newContactProperties.Add("parentcustomeridtype", organizationType);
newContactProperties.Add("parentcustomerid", orgReference);
var entity = new Entity();
entity.LogicalName = "contact";
entity.Attributes = new AttributeCollection();
entity.Attributes.AddRange(newContactProperties);
client.Create(entity);
This gives me error 'Attribute parentcustomeridtype must not be NULL if attribute parentcustomerid is not NULL'
I am puzzled why this happens and how I can solve this problem. Please help me if you can.
Thank you,
AllWorkNoPlay
You don't need to set "parentcustomeridtype" attribute separately. It's a system field, will be set by platform and in parentcustomerid exists for legacy reason, when it was Customer type in earlier versions of Dynamics CRM.
You need to specify only EntityReference in lookup field.
newContactProperties.Add("parentcustomerid", new EntityReference("account", new Guid("{accountid guid}")));
Also it's not clear what type you use in "orgReference" field. For contact valid entity types should be "account" or "contact".
thank you for the answers, I did not manage to get it right using web services this way.
I tried using Early Bound access with success:
Generated proxy objects using https://xrmearlyboundgenerator.codeplex.com/
Added line [assembly: Microsoft.Xrm.Sdk.Client.ProxyTypesAssemblyAttribute()] to assemblyInfo to have Intellisense available (even for customized fields)
Now I manage to create a contact and assign it to an organization (something like this):
var contact = new Contact()
{
FirstName = "Bob",
LastName = "Dobalina",
Address1_Line1 = "123 Strasse",
Address1_City = "Berlin",
Address1_PostalCode = "32254",
Telephone1 = "425-555-5678",
EMailAddress1 = "bob.dobalina#germany.de"
};
var account = new Account()
{
Name = "Siemens Germany",
};
context.AddObject(contact);
context.AddObject(account);
context.AddLink(account, "contact_customer_accounts", contact);
context.SaveChanges();
}

How to mock a validator for unit testing

I have a method that validate an Object calling an external service:
public void Validate(IValidator<MyType> validator)
{
IMapper<MyType> mapper = new MyTypeMapper();
foreach (var element in this.Elements)
{
ValidationResult result = validator.Validate(myTypeInstance, mapper, new ValidationConfiguration());
if (result.IsValid)
// do something
else
// do something else
}
}
Now in my unit test I have a collection of elements. And I want that if an element have a given id number the Validate method should return another stub with validation messages:
// arrange
var myAggregate aggregate = ElementsNonValidated.Stub();
var mockedValidator = new Mock<IValidator<MyType>>();
mockedValidator.Setup(a => a.Validate(
It.Is<Mytype>(x => x.Id == Guid.Parse("3F2504E0-4F89-11D3-9A0C-0305E82C3301")),
new Mapper(),
new ValidationConfiguration()
)).Returns<ValidationResult>(x => x = new ValidationResult());
// act
myAggregate.Valida(mockedValidator.Object);
The problem is: When unit test starts and go forth till the real method validate still return result=null. Why? What's wrong with my mock?
The problem is here:
mockedValidator.Setup(a => a.Validate(
It.Is<Mytype>(x => x.Id == Guid.Parse("3F2504E0-4F89-11D3-9A0C-0305E82C3301")),
new Mapper(),
new ValidationConfiguration()
)).Returns<ValidationResult>(x => x = new ValidationResult());
You setup Validate to expect specific Mapper and ValidationResult instances, which of course do not match the instances used in your system under test. If you don't care what instance should be used for a parameter, use It.IsAny<>:
mockedValidator.Setup(a => a.Validate(
It.Is<Mytype>(x => x.Id == Guid.Parse("3F2504E0-4F89-11D3-9A0C-0305E82C3301")),
It.IsAny<Mapper>(),
It.IsAny<ValidationConfiguration>()
)).Returns<ValidationResult>(x => x = new ValidationResult());
This will return a new ValidationResult for any and every invocation to Validate where the object's Id is equal to that particular GUID.
The reason for the TargetParameterCountException is in your Returns statement, and is answered here.

docrtine 2 versioning associations

I need to implement versioning for some entities.
I have an entity "Map" which has a OneToMany association with "Spot" Entities.
The "Map" and also "Spot" should be versionable.
It should be possibler to show older versions of a "Map" with all the asociated "Spots" on it.
So on an old version the "Map" itself could have another backgound-image, but also the position or number of associated "Spots" can differ.
I like this approach of the AuditLog (at the end of the page):
http://www.doctrine-project.org/blog/doctrine2-versionable.html
[php]
class AuditListener implements EventSubscriber
{
public function getSubscribedEvents()
{
return array(Events::onFlush);
}
public function onFlush(OnFlushEventArgs $args)
{
$em = $args->getEntityManager();
$uow = $em->getUnitOfWork();
$changeDate = new DateTime("now");
$class = $em->getClassMetadata('DoctrineExtensions\Auditable\AuditEntry');
foreach ($uow->getScheduledEntityUpdates() AS $entity) {
if ($entity instanceof Auditable) {
$changeSet = $uow->getEntityChangeSet($entity);
foreach ($changeSet AS $field => $vals) {
list($oldValue, $newValue) = $vals;
$audit = new AuditEntry(
$entity->getResourceName(),
$entity->getId(),
$oldValue,
$newValue,
$changeDate
);
$em->persist($audit);
$em->getUnitOfWork()
->computeChangeSet($class, $audit);
}
}
}
}
}
I wonder how to handle association of the versionable entity.
For Example:
When a "Map" changes, a new Map Version is saved, but what about the Association to the Spots?
When a "Spot" changes, what about its parent "Map".
When buliding the new Version of "Map":
- how can I figure out that it has Association?
- how can I figure out that a Association is also Versionable
- how do I handle the Associatons
Even if an association is not versionable, if I change an associated non-versionable entity I also change the old versions of "Map" because they are also still associated.
Does anyone has experience or ideas how to manage that with doctrine 2.1?

OAuth making requests against LinkedIn API cause 401 error

I am creating an application for a client that integrates with the LinkedIn API. I got through the authentication without too many problems, but everything there is working and now I need to make the actual requests. Primarily I am working in the Share API. I create the HTTP call with the following method:
public any function sendRequest(any req){
var param = false;
var headParams = [];
var bodyParams = [];
var call = new http(proxyserver='192.168.201.12', proxyport=8888);
var i = 1;
call.setUrl(Arguments.req.getRequestUrl());
call.setMethod(Arguments.req.getMethod());
getSigner().signRequest(Arguments.req);
headParams = Arguments.req.getParameters(true);
bodyParams = Arguments.req.getParameters();
if(arrayLen(bodyParams)){
call.addParam(
type='header',
name='Authorization',
value="OAuth#Variables.encoder.encodedParameter(Arguments.req.getParameters(true), true, false, true)#"
);
}
// Header parameters
if(!arrayLen(bodyParams)){
for(i=1; i<=arrayLen(headParams); i++){
param = headParams[i];
call.addParam(
type=Arguments.req.getParameterType(),
name=Variables.encoder.parameterEncodedFormat(param.name),
value=param.value
);
}
}
// Body parameters (should only be 1)
if(arrayLen(bodyParams)){
for(i=1; i<=arrayLen(bodyParams); i++){
param = bodyParams[i];
call.addParam(
type='xml',
value=param.value
);
}
}
return call.send().getPrefix();
}
When I sign the request, I use the following method:
public void function signRequest(any req){
var headParams = Arguments.req.getParameters(true);
var bodyParams = Arguments.req.getParameters();
var secret = "#Variables.encoder.parameterEncodedFormat(getConsumer().getConsumerSecret())#&#Variables.encoder.parameterEncodedFormat(Arguments.req.getOAuthSecret())#";
var base = '';
params = Variables.encoder.encodedParameter(headParams, true, true);
params = "#params#&#Variables.encoder.parameterEncodedFormat(bodyParams[1].value)#";
secret = toBinary(toBase64(secret));
local.mac = createObject('java', 'javax.crypto.Mac').getInstance('HmacSHA1');
local.key = createObject('java', 'javax.crypto.spec.SecretKeySpec').init(secret, local.mac.getAlgorithm());
base = "#Arguments.req.getMethod()#&";
base = base & Variables.encoder.parameterEncodedFormat(Arguments.req.getRequestUrl());
base = "#base#&#Variables.encoder.parameterEncodedFormat(params)#";
//writeDump(base) abort;
local.mac.init(local.key);
local.mac.update(JavaCast('string', base).getBytes());
Arguments.req.addParameter('oauth_signature', toString(toBase64(mac.doFinal())), true);
}
I have tried signing it with only the header parameters (usual OAuth params) and include the body parameter (xml string), but everything gives me a 401 error, so I was wondering what I should be using in my base string that gets signed for the request?
Not a proper answer to your question, but may help you.
In my case after many unsuccessful tries of using the LinkedIn API with CF8, I finally gave up / didn't have more time for it. Instead of a "proper" integration I've used the linkedin-j Java library. It finally got me going and I didn't encounter any more signing issues.
Btw for all my integrations requiring OAuth I've used this library and didn't have any signing issues as with LinkedIn API.