How to set JsonSerializer default settings globally - jsonserializer

For System.Text.Json.JsonSerializer, I have to set the options every time I serialize or deserialize or have to set attributes on every property of the object, due to lack of a way to set/change the default settings. At least I am not able to find one.
JsonSerializer.Deserialize<TypeListDTO>(
"{\"listNo\":33}",
new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase});
Is there such a way available? If not, is there a workaround available?
EDIT: I am using .Net Core 3 with Endpoint Routing. But could very well not be using it at all.

Try it with AddJsonOptions(Action) in Startup.ConfigureServices:
services.AddMvc()
.AddJsonOptions( options =>
{
options.SerializerSettings.Formatting = Formatting.Indented;
options.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});

Related

How can I enable automatic slicing on Elasticsearch operations like UpdateByQuery or Reindex using the Nest client?

I'm using the Nest client to programmatically execute requests against an Elasticsearch index. I need to use the UpdateByQuery API to update existing data in my index. To improve performance on large data sets, the recommended approach is to use slicing. In my case I'd like to use the automatic slicing feature documented here.
I've tested this out in the Kibana dev console and it works beautifully. I'm struggling on how to set this property in code through the Nest client interface. here's a code snippet:
var request = new Nest.UpdateByQueryRequest(indexModel.Name);
request.Conflicts = Elasticsearch.Net.Conflicts.Proceed;
request.Query = filterQuery;
// TODO Need to set slices to auto but the current client doesn't allow it and the server
// rejects a value of 0
request.Slices = 0;
var elasticResult = await _elasticClient.UpdateByQueryAsync(request, cancellationToken);
The comments on that property indicate that it can be set to "auto", but it expects a long so that's not possible.
// Summary:
// The number of slices this task should be divided into. Defaults to 1, meaning
// the task isn't sliced into subtasks. Can be set to `auto`.
public long? Slices { get; set; }
Setting to 0 just throws an error on the server. Has anyone else tried doing this? Is there some other way to configure this behavior? Other APIs seem to have the same problem, like ReindexOnServerAsync.
This was a bug in the spec and an unfortunate consequence of generating this part of the client from the spec.
The spec has been fixed and the change will be reflected in a future version of the client. For now though, it can be set with the following
var request = new Nest.UpdateByQueryRequest(indexModel.Name);
request.Conflicts = Elasticsearch.Net.Conflicts.Proceed;
request.Query = filterQuery;
((IRequest)request).RequestParameters.SetQueryString("slices", "auto");
var elasticResult = await _elasticClient.UpdateByQueryAsync(request, cancellationToken);

How to implement versioning for Token endpoint in Web API 2

I have a Asp.Net Web API 2 using Token based authentication (OAuth2).
I have implemented Web API versioning using aspnet-api-versioning.
So now I have three different versions of my API. It's really great, I can now change V3 without affecting the current API.
But the /token endpoint is not versioned because it is not in my controller. It's in the Providers.
I searched but couldn't find anything helpful.
We can register more than one token endpoint in the Startup.Auth.cs
So here's what I did:
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(TokenExpirationInDays),
AllowInsecureHttp = true, //Allow HTTP to send username password.
};
app.UseOAuthBearerTokens(OAuthOptions);
OAuthOptionsV3 = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/api/V3/Accounts/Token"),
Provider = new ApplicationOAuthProvider2(PublicClientId),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(TokenExpirationInDays),
AllowInsecureHttp = true, //Allow HTTP to send username password.
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptionsV3);
So now I have different token endpoint for each version.
I'm not familiar with this particular setup, but this looks like middleware. There isn't quite enough information here to provide you with a specific answer, but your goals should be achievable in one of a few ways:
Option 1 - Use the Conventions API
If you authorization endpoint is actually a controller (though I think it is not), you can use the Conventions API like so:
services.AddApiVersioning(options =>
{
options.Conventions.Controller<OAuthController>().IsApiVersionNeutral();
}
Conventions was specifically meant to deal with a scenario where a controller might be externally defined and you don't have any control over the source code.
Option 2 - Use a Custom Convention
Middleware could create actions dynamically. As long as actions are actually produced, then you can use a custom IControllerConvention. You would be passed the ControllerModel which contains the actions you need to version. Assuming this is the correct behavior, you'd be looking for matching actions in the source model and then you can apply it to the controller conventions with something like:
public class MyConventions : IControllerConvention
{
public bool Apply(IControllerConventionBuilder controller, ControllerModel controllerModel)
{
var method = // TODO: resolve the target method from controllerModel
if (method == null)
{
return false;
}
controller.Action(method).IsApiVersionNeutral();
return false;
}
}
Option 3 - In Middleware
If this is pure middleware, API versioning isn't directly supported there. You can, however, support versioning on your own if the pipeline is composed properly. Specifically, API Versioning must come before other parts of middleware that need it. This usually happens automatically, but if you need to control registration, you need to change your setup to handle it manually like this:
services.AddApiVersioning(options => options.RegisterMiddleware = false);
// ... inside application setup
services.UseApiVersioning();
The API Versioning middleware doesn't really do much of anything special. It merely adds a pipeline feature. As long as that's before your other middleware, it will be available downstream like this:
var feature = context.Features.Get<IApiVersioningFeature>();
// the raw, unparsed API version, if any
var rawApiVersion = feature.RawApiVersion;
// the parse API version; will be null if no version is specified
// or the value cannot be parsed
var apiVersion = feature.ApiVersion;
// TODO: enforce versioning policies within the middleware
Option 4 - Use the API Explorer
If none of the previous approaches will work for you, you can leverage the API Explorer extensions for API Versioning to build your configuration (as above) from discovered APIs. This would have the advantage of not being hardcoded or require changes every time you release a new version.
Your application startup configuration would change to something like this:
public void Configure(IApplicationBuilder app, IApiVersionDescriptionProvider provider)
{
foreach (var description in provider.ApiVersionDescriptions)
{
var options = new OAuthAuthorizationServerOptions()
{
TokenEndpointPath = new PathString($"/api/{description.GroupName}/Accounts/Token"),
Provider = new ApplicationOAuthProvider2(PublicClientId),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(TokenExpirationInDays),
AllowInsecureHttp = true,
};
app.UseOAuthBearerTokens(options);
}
}

Is it possible to track changes to Entity Metadata in Dynamics CRM?

Is there any way to track changes to Metadata, like new fields, new entities and so on?
It is difficult to control a very large project in the same environment, so sometimes there are some customization that should not be deployed to productions (Mostly are mistakes or test in a development environment).
And there is a way to know who did that customization?
I am looking to know every possible change, not any in particular.
You have to use the RetrieveMetadataChangesRequest and it is not possible to know who made the change.
This is available only from Microsoft Dynamics CRM 2011 Update Rollup 12
This request is intended to be used to cache information from the metadata and be able to work offline, but we can use it to track changes to metadata in complex projects and complex teams
Examples on internet are not very friendly so this is how you can use the request:
The request can be completed only with filling one parameter
RetrieveMetadataChangesRequest req = new RetrieveMetadataChangesRequest()
{
ClientVersionStamp = null
};
var response = (RetrieveMetadataChangesResponse)service.Execute(req);
The first time you executed this request ClientVersionStamp needs to be null, because there was no request made to the metadata before and there is no ClientVersionStamp. This parameter is the last time you query for metadata changes and if it is null it will bring all customization from all time, so probably this request won't complete on time so we need to tune up.
var EntityFilter = new MetadataFilterExpression(LogicalOperator.And);
EntityFilter.Conditions.Add(new MetadataConditionExpression("SchemaName", MetadataConditionOperator.Equals, "ServiceAppointment"));
var entityQueryExpression = new EntityQueryExpression()
{
Criteria = EntityFilter
};
RetrieveMetadataChangesRequest req = new RetrieveMetadataChangesRequest()
{
Query = entityQueryExpression,
ClientVersionStamp = null
};
var response = (RetrieveMetadataChangesResponse)service.Execute(req);
This will query all metadata changes for "ServiceAppointment", feel free to use the entity you want, but what we need is the ServerTimeStamp from the response, it will looks like "22319800!09/13/2017 16:17:46", if you try to send this time stamp first, it will throw an exception, so it is necessary to query first to get a server time stamp.
Now you can use the request and the time stamp to retrieve all new changes since "22319800!09/13/2017 16:17:46"
RetrieveMetadataChangesRequest req = new RetrieveMetadataChangesRequest()
{
Query = entityQueryExpression,
ClientVersionStamp = #"22319800!09/13/2017 16:17:46"
};
var response = (RetrieveMetadataChangesResponse)service.Execute(req);
You can filter the query to match your needs, only search for specific entities, labels, relationship, keys and attributes or specific properties.
EntityQueryExpression entityQueryExpression = new EntityQueryExpression()
{
Criteria = EntityFilter,
Properties = EntityProperties,
RelationshipQuery = new RelationshipQueryExpression()
{
Properties = RelationshipProperties,
Criteria = RelationshipFilter
},
AttributeQuery = new AttributeQueryExpression()
{
Properties = AttributeProperties,
Criteria = AttributeFilter
}
};
Use this request and implement it the way you need.
A couple more options:
Register a plugin on Publish and Publish All, and track who did
the publish and when. That may help you narrow down who was making
changes, although someone could technically make a change without
publishing it, so not perfect information.
If you're using Dynamics OnPremise, the Metadata tables sometimes store information about who made a change that is not visible through a Metadata retrieve. I've found this to be very spotty though, not all Metadata has a Modified By user stored.

Dnn 8: caching module settings

I put some module settings via
var moduleController = new ModuleController();
moduleController.UpdateModuleSetting(moduleId, "key", value);
Later if I try to access the setting using
var rcModule = ModuleController.Instance.GetModuleByDefinition(PortalSettings.PortalId, "MyModule");
var value = rcModule.ModuleSettings["value"]?.ToString() ?? string.Empty;
the same value is returned (even if I resave the setting) until I clear the app cache. The value is correct after every saving settings in the database but not in the module. I also tried to add ModuleController.SynchronizeModule(moduleId); to my save settings method but it didn't help. Module and page cache both disabled.
What's wrong?
You are creating a new instance of moduleController, not getting the existing one from memory.
You can clear the cache programmatically.
DotNetNuke.Common.Utilities.DataCache.ClearModuleCache(TabId);
DotNetNuke.Common.Utilities.DataCache.ClearTabsCache(PortalId);
DotNetNuke.Common.Utilities.DataCache.ClearPortalCache(PortalId, false);
Or get the correct instance and edit the properties.
ModuleInfo moduleInfo = ModuleController.Instance.GetModule(ModuleId, TabId, false);
moduleInfo.ModuleTitle = "New Title";
ModuleController.Instance.UpdateModule(moduleInfo);

Java Caching System(JCS) - Create regions programmatically

We are planning to use some caching mechanism in our application, and chosen Java Caching System(JCS) after performing comparison study among many other caching solutions. Every thing is fine when I use external configuration (cache.ccf) to define cache regions and its properties( like maxlife, ideltime, etc).
But the requirement is changed to have dynamic cache regions, that is we would need to define cache regions and its properties at run time. I am not able to find more details or samples regarding this operation.
I successfully created cache regions at run time ( using below method signature).
ICompositeCacheAttributes cattr=..
IElementAttributes attr = new ElementAttributes();
attr.setIsEternal(false);
attr.setMaxLifeSeconds( maxLife );
defineRegion(name, cattr,attr);
But the problem is, IElmentAttributes does not sets to the cache. I did research on source of JCS and found attr is never set. It is non used argument!! bit strange
After some more googling, I found below options to set the attributes manually, but still did not work
IElementAttributes attr = new ElementAttributes();
attr.setIsEternal(false);
attr.setMaxLifeSeconds( maxLife );
jcs.setDefaultElementAttributes(attr);
All I want is to set maxLifeSeconds for created regions.
I found way through for my problem, we need to set attributes when you put the data in to cache. See the implementation for somebody who is interested,
JCS jcs = JCS.getInstance("REGION");
IElementAttributes attr = new ElementAttributes();
attr.setIsEternal(false);
attr.setMaxLifeSeconds( maxLife );
jcs.put("Key",data, attr);
Sample code here
Properties props = new Properties();
//
// Default cache configs
//
props.put("jcs.default", "");
props.put("jcs.default.cacheattributes","org.apache.jcs.engine.CompositeCacheAttributes");
props.put("jcs.default.cacheattributes.MaxObjects","1000");
props.put("jcs.default.cacheattributes.MemoryCacheName", "org.apache.jcs.engine.memory.lru.LRUMemoryCache");
props.put("jcs.default.cacheattributes.UseMemoryShrinker", "true");
props.put("jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds", "3600");
props.put("jcs.default.cacheattributes.ShrinkerIntervalSeconds", "60");
props.put("jcs.default.cacheattributes.MaxSpoolPerRun", "500");
//
// Region cache
//
props.put("jcs.region.myregionCache", "");
props.put("jcs.region.myregionCache.cacheattributes", "org.apache.jcs.engine.CompositeCacheAttributes");
props.put("jcs.region.myregionCache.cacheattributes.MaxObjects", "1000");
props.put("jcs.region.myregionCache.cacheattributes.MemoryCacheName", "org.apache.jcs.engine.memory.lru.LRUMemoryCache");
props.put("jcs.region.myregionCache.cacheattributes.UseMemoryShrinker", "true");
props.put("jcs.region.myregionCache.cacheattributes.MaxMemoryIdleTimeSeconds", "3600");
props.put("jcs.region.myregionCache.cacheattributes.ShrinkerIntervalSeconds", "60");
props.put("jcs.region.myregionCache.cacheattributes.MaxSpoolPerRun", "500");
props.put("jcs.region.myregionCache.cacheattributes.DiskUsagePatternName", "UPDATE");
props.put("jcs.region.myregionCache.elementattributes", "org.apache.jcs.engine.ElementAttributes");
props.put("jcs.region.myregionCache.elementattributes.IsEternal", "false");
...
// Configure
CompositeCacheManager ccm = CompositeCacheManager.getUnconfiguredInstance();
ccm.configure(props);
// Access region
CompositeCache myregionCache = ccm.getCache("myregionCache");
...

Resources