Windsor WcfFacility: Setting ServiceBehavior properties - castle-windsor

I'm hosting a service using Windsor's WCF Facility, but I can't get UseSynchronisationContext and ConcurrencyMode set that one would normally do using the ServiceBehaviorAttribute. I've seen two options that apparently should work (but tried both to no avail):
Registering ServiceBehaviorAttribute as a Component for IServiceBehavior
Modifying the Description collection of Behaviors in the OnCreated configuration callback in the WCF registration.
A third method that I've tried is using AddExtensions, but that results in an exception because there's already a ServiceBehaviorAttribute (by default?) in the list of Behaviors. This is also the case with method 2, but in that case I can remove it and add a new one, or modify the existing entry.
It's really frustrating that there doesn't seem any documentation on this except a line stating 'Remove the ServiceBehaviorAttribute' from your services, apparently because it can conflict with the WcfFacility.
Can someone point me on how to properly do this? Any hint is appreciated!

Unfortunately I didn't properly test. Modifying the properties of the ServiceBehaviorAttribute in the list of Behaviors of the Description property in the OnCreated action actually works as intended.
Sample registration:
container.Register(Component.For<IWCFWarehouseServiceAsyncCallback>()
.ImplementedBy<WarehouseService>()
.AsWcfService(new DefaultServiceModel()
.AddBaseAddresses(baseAddress)
.OnCreated(host =>
{
var sb = host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
sb.UseSynchronizationContext = false;
sb.ConcurrencyMode = ConcurrencyMode.Reentrant;
})
.AddEndpoints(WcfEndpoint.BoundTo(binding).At("WarehouseService"))));

Related

Blazor WebAssembly JsonException: A possible object cycle was detected which is not supported

I get this error because I have circular references defined in my object model. My question is, is there any way to resolve this using one of the following two options?
Using Newtonsoft.Json and options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
Using System.Text.Json and options.JsonSerializerOptions.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.Preserve;
I'm not seeing a way to switch to Newtonsoft.Json in a Blazor WebAssembly application and I tried implementing option 2 in the ConfigureServices function of Startup.cs in my Server project but I still kept getting the error.
I'm just trying to find a solution that doesn't require me redefining my object model. The JsonIgnore attribute does not appear to be an option either because I assume, and it appears, that then any fields I define it on do not exist in the Json on the client which breaks my application.
Update: I found this site which looks to me like discusses exactly what I'm referring to here and how to implement the solution but I have not got it to work yet. If anyone is successfully using Blazor WebAssembly with circular references in your object model please let me know what you're doing.
https://github.com/dotnet/aspnetcore/issues/28286
Thank you for pointing out this error in Blazor. I found the answer in the issue you mentioned (this comment). You need to change json options also on the Client side. This works for me:
On server
services.AddControllersWithViews().AddJsonOptions(options =>
{
options.JsonSerializerOptions.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.Preserve;
options.JsonSerializerOptions.PropertyNamingPolicy = null;
});
On client
var response = await Http.GetFromJsonAsync<T>("{Address}", new JsonSerializerOptions
{
ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.Preserve,
PropertyNamingPolicy = null
});
To the two options you mentioned there is a third option available if you use .NET 6 or above.
Using System.Text.Json and options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
Beware that ignoring cycles have issues on its own (such as data corruption) but if you were depending on it when you were using Newtonsoft.Json then you will be fine as it is basically the same behavior.
If you prefer to go with ReferenceHandler.Preserve, please share more info on what error you are getting and I can try to help you out.
One way to go about this is specify how much depth an object is allowed to have. Please see the documentation here regarding how to do this with System.Text.Json. I think this may help.

.NET CORE 3 Upgrade CORS and Json(cycle) XMLHttpRequest Error

I had my working project written in asp.net core 2.1 for a long time, but yesterday, I was forced to upgrade it to .net core 3.0 (due to 2.1 cannot call Dll' s which are written in 3.0 already).
With that, a lot of functions were obsolete or already removed. I fixed almost all of it, but one problem with CORS.
Like many people before me, I used:
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
in Configure function. And services.AddCors() in ConfigureServices function.
I was able to fixed this quite easily with setting WithOrigins() or .SetIsOriginAllowed(_ => true) instead of AllowAnyOrigin() which does not work anymore with AllowCredentials().
After that, I was able to start the application and I thought everything is fine, but then I get stuck until now with problem I do not know, how to fix.
I have DB relation N:N and relation table which handle that, that means I have Admin entity with AdminProject list property, then I have AdminProject entity with Admin list and Project list properties and Project entity with AdminProject list property once again.
When I am listing my projects of certain admin, I am returning in Controller this return Ok(projects), where I just use getAll on AdminProject entity and then with Select return only project.
For that, I have to use[JsonIgnore] in project/admin for properties which I do not need to avoid cycling when creating json.
With that said: NOW IN .NET CORE 3.0 AND CORS SETTINGS IT DOES NOT WORK.
I am getting an error:
System.Text.Json.JsonException: A possible object cycle was detected which is not supported. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32.
when debugging in console and error Access to XMLHttpRequest at 'http://localhost:5000/api/project/adminlist/1' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. in WEB browser
I think I tried almost everything with Cors settings etc and I do not know why is this happening now. I also tried to JsonConvert.SerializeObject() before return it ---> return Ok(JsonConvert.SerializeObject(projects)) and this is working, but I am not able (mentally) to do this in every single controllers functions.
Please help! Thanks a lot!
The problem was occurring because in .NET Core 3 they change little bit the JSON politics. Json.Net is not longer supported and if you want to used all Json options, you have to download this Nuget: Microsoft.AspNetCore.Mvc.NewtonsoftJson.
After that in your Startup.cs file change/fix/add line where you are adding MVC (in the ConfigureServices method.
So: here is what I did and what fixed my issue:
services.AddMvc(option => option.EnableEndpointRouting = false)
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
.AddNewtonsoftJson(opt => opt.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore);
I hope it will help somebody else.
Cheers!
A couple other things have changed in .net core 3 and now instead of using addMVC you can use addControllers. So your code might look like the follow:
services.AddControllers().AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);

How to get settings in middleware?

I'm sure this has got to be a duplicate, but I've been searching way too long and still can't find the answer.
I want to access configuration options (from a json file, although I don't think the source matters in regard to my question) from here:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Run(async context =>
{
// Get my config values here and do something with them
await Task.CompletedTask;
});
}
I could use var x = Config.GetValue<string>("AppSettings:MySetting:0"); but because it's a list I would have to create a loop and retrieve values until I get a null value and all that so I would rather do the IOptions thing so it loads it in a strongly typed class for me. I have this code in ConfigureServices:
services.AddOptions();
services.Configure<AppSettings>(Config.GetSection("AppSettings"));
but I just don't know how to get at the object that's registered there from within the Configure method.
I also tried inspecting the value of Config.GetSection("AppSettings") while debugging and found that under the json provider I could see my settings. However, while that's available in the inspector, I can't see how I can directly access my list. That is, I can access my list one value at a time using GetValue() but I can't just access the whole list as one value.
As often seems to happen, I finally figured out what I was looking for right after making a post here. Basically, I don't need IOptions or anything else having to do with DI for my scenario. I just needed to use .Bind() to bind the settings to an instance of my class:
AppSettings a = new AppSettings();
Config.GetSection("AppSettings").Bind(a);

Custom JSON renderer in AEM/Sling

I've been playing around with this for a while now, and I think, I've - almost - cracked it, but I am still not fully satisfied with my solution.
So, what I want to do, is having a piece of content, a list of items, which would have two views: The standard HTML one, so people can view and edit it; and then a JSON endpoint for other services to consume.
First I thought it's a simple matter of creating two JSP scripts to render the content:
/apps/my-stuff/components/list-page/html.jsp
/apps/my-stuff/components/list-page/json.jsp
However the Apache Sling DefaultServlet seems to be rather ignorant of the json.jsp script.
As a second attempt, I created another script, in /apps/foundation/components/primary/cq/Page/json.jsp which will be actually called, and renders the page, as I expected. However there are a couple of worries/questions regarding this:
First of all, why is this being honoured by the system, and not the one in the more specific place?
The documentation states, that to find the appropriate renderer, first sling:resourceType will be inspected, then sling:resourceSuperType and then, only as a fallback will jcr:PrimaryType checked. However I think this is rather: jcr:PrimaryType, then the DefaultServlet, and then all the other things.
Most worryingly however, I have to admit, this is rather generic, so it'll break all the contnet with jcr:PrmaryType = Page, so that could have some side-effects.
A solution could be creating a new type: ListPage extends Page; and then create a renderer for that in /apps/foundation.... However I have this bad feeling, that might introduce other problems.
So my question is two fold: What is the proper way of doing this, and/or what am I missing from the way the URL -> script resolution is working in AEM/Sling. (Because it seems to be slightly different that described here and here.)
(Obviously I am trying to keep the default JSON renderer for other pages, as that might be needed for other things in the page. I am not even sure, changing this one page won't break the UI for this particular page...)
However the Apache Sling DefaultServlet seems to be rather ignorant of the json.jsp script.
Have you tried renaming your JSP like so: "list-page.json.jsp"?
If you're using AEM 6.3, you should look at Sling model Exporters. They allow you to automatically register a servlet against your Sling Model (that you can create to model your list content). That servlet can generate a JSON representation of the model for you using Jackson.
If you're not using AEM 6.3, I would suggest you create a servlet registered against your resource type and use an additional selector.
#SlingServlet(
selectors = "json",
resourceType = "my-stuff/components/list-page",
methods = "GET")
More information on Sling Servlets can be found here.

Web API seems to be caching JsonFormatter with OData requests?

TL;DR: My OData requests seem to be hitting my custom JsonFormatter once and only once per OData GET method (per controller), which results in "stuck" (cached?) custom formatting.
I am working on a Web API project, and have implemented and registered my own JsonMediaTypeFormatter:
config.Formatters.Clear();
config.Formatters.Add(MyJsonFormatter);
'MyJsonFormatter' has custom implementations of the following:
`-> SerializerSettings
`-> ContractResolver
`-> CreateProperty
In my protected override CreateProperty(MemberInfo member, MemberSerialization memberSerialization) method, I restrict certain properties from being serialized based on user permissions.
This works great for all my API endpoints except for my OData enabled GET requests. Each controller has a GET method using the Primary Keys of the object, and an OData GET method which has a format similar to the following:
[HttpGet, Route]
public PageResult<Customer> GetOData(ODataQueryOptions<Customer> options)
{
IQueryable qCustomer = options.ApplyTo(_args.Context.Customers);
return new PageResult<Customer>(qCustomer as IEnumerable<Customer>, Request.GetNextPageLink(), Request.GetInlineCount());
}
If I put a breakpoint on my overwritten CreateProperty method, it gets hit with every API request. However, it will only get hit once per OData GET method per controller. So a subsequent call from a different user with different permissions skips my code and gives me the formatting used in the first call.
If I restart the API, I can again hit the breakpoint (once), and get my formatting permissions for the user the call was made by, but subsequent calls (no matter the user) do not hit my breakpoint. Obviously, restarting the API for every OData request is not a solution I can live with.
I have put almost a full day into researching this, and have found several posts (here, here, here, etc.) which lead me to believe I need to implement my own ODataMediaTypeFormatter.
However, if this is the case, why is it hitting my JsonFormatter breakpoint? It seems like it uses my formatter, somehow caches my format permissions for that controller, and uses them from then on.
(Secondly, creating my own ODataFormatter does not seem to be a valid option anymore, since the codebase has apparently changed since this post - CreateEdmTypeSerializer does not exist. (I'm using Microsoft ASP.NET Web API 2.1 OData, version 5.1.2).)
Question: Is there a way I can get OData to play nicely with my JsonFormatter, and run through my custom CreateProperty code for each request?
If someone can at minimum explain what is going on here, it may help to point me in the direction I need to go, but right now my brain is just melting. :P
Update: I published to IIS and found that if I recycle the app pool, the formatting seems to be refreshed. So it definitely seems that something is being cached, the question is 'what' and 'why' - do PageResults automatically get cached? How do I stop whatever is being cached from being cached?
I don't know that my question was asked very well, as at the time I didn't entirely know what I was looking for or what was going wrong... However, since then, I have found an answer and figured I would post in just in case someone else runs into my issue.
The issue I was having is that I need to not serialize specific properties in my webapi Json response based on the permissions of the caller. The problem was, the first call upon running the API worked fine, however subsequent calls were not hitting my breakpoints, and were being returned with the permissions of the first request.
The resolution I found was to override another method in my ContractResolver to disable caching for the types I didn't want cached (in this case, anything with Entity as its base class).
public class SecurityContractResolver : DefaultContractResolver
{
public override JsonContract ResolveContract(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
if (type.IsSubclassOf(typeof(Entity)))
return CreateContract(type); //don't use cache in base method - we need different contract resolution per user / permissions
return base.ResolveContract(type); // <-- the base class calls CreateContract and then caches the contract
}
.....
}
Seems to be working great so far. Hope this helps someone!