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!
Related
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"))));
I am using Grails 2.2.4 and have a controller endpoint which converts a domain object list to JSON. Under load (as little as 5 concurrent requests) the marshaling performance is very poor. Taking thread dumps the threads are blocked on:
java.lang.ClassLoader.loadClass(ClassLoader.java:291)
There is a single marhsaler registered to marshal all domain objects using reflection and introspection. Realizing that reflection and introspection is slower than direct method calls, I am still seeing unexpected behavior in that the class loader is caller every time and in turn blocking occurs. An example stacktrace is as follows:
java.lang.Thread.State: BLOCKED (on object monitor)
at java.lang.ClassLoader.loadClass(ClassLoader.java:291)
- waiting to lock <785e31830> (a org.grails.plugins.tomcat.ParentDelegatingClassLoader)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at java.beans.Introspector.instantiate(Introspector.java:1470)
at java.beans.Introspector.findExplicitBeanInfo(Introspector.java:431)
at java.beans.Introspector.<init>(Introspector.java:380)
at java.beans.Introspector.getBeanInfo(Introspector.java:167)
at java.beans.Introspector.getBeanInfo(Introspector.java:230)
at java.beans.Introspector.<init>(Introspector.java:389)
at java.beans.Introspector.getBeanInfo(Introspector.java:167)
at java.beans.Introspector.getBeanInfo(Introspector.java:230)
at java.beans.Introspector.<init>(Introspector.java:389)
at java.beans.Introspector.getBeanInfo(Introspector.java:167)
at java.beans.Introspector.getBeanInfo(Introspector.java:230)
at java.beans.Introspector.<init>(Introspector.java:389)
at java.beans.Introspector.getBeanInfo(Introspector.java:167)
at org.springframework.beans.CachedIntrospectionResults.<init>(CachedIntrospectionResults.java:217)
at org.springframework.beans.CachedIntrospectionResults.forClass(CachedIntrospectionResults.java:149)
at org.springframework.beans.BeanWrapperImpl.getCachedIntrospectionResults(BeanWrapperImpl.java:324)
at org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:727)
at org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:721)
at org.springframework.beans.PropertyAccessor$getPropertyValue.call(Unknown Source)
at com.ngs.id.RestDomainClassMarshaller.extractValue(RestDomainClassMarshaller.groovy:203)
...
...
A simple benchmark loading the same endpoint with the same parameters results in the loadClass call.
I was under the impression the classes would be at least cached by the class loader and not loaded on every method call to get the property to be marshaled.
The code to retrieve the property value is as follows:
BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(domainObject);
return beanWrapper.getPropertyValue(property.getName());
Is there a configuration setting that is needed to ensure the classes are only loaded once? or perhaps a different way to get the property that doesn't result in class loading every time? Or perhaps a more performant way to achieve this?
Writing a custom marshaler per domain class would avoid the reflection and introspection but is going to be a lot of repeat code.
Appreciate any input.
So after much digging this is what I found out.
Using the BeanUtils.getPropertyDescriptors and getValue will always try and find a BeanInfo class describing the bean using the class loader. In this case we don't provide BeanInfo classes for our grails domain classes so this call is redundant. I found some information where you can provide a custom BeanInfoFactory to bypass this and exclude your packages but I couldn't find how to configure it with Grails.
Also searching the springframework documentation there is a configuration option you can pass Introspector.IGNORE_ALL_BEANINFO that will tell CachedIntorspectionResults to never look up the bean classes. However this was not available in version 3.1.4 of springframework which was current for grails 2.2.4. The newer versions do appear to have this option.
So, if using BeanUtils you can't by pass this initial lookup on the class loader. However subsequent loaders should be cached by CachedIntrospectionResults. Unfortunately this doesn't happen in our scenario. There looks to be a bug in the test to see if the lookup is cacheable. See more info on this below.
The fix was ultimately to fall back to use pure reflection. Rather than use:
beanWrapper.getPropertyValue(property.getName());
To use:
PropertyDescription pd = BeanUtils.getPropertyDescriptor(domainObject.getClass(), property.getName())
pd.readMethod.invoke(domainObject)
Where the pd is cached.
After fixing this the profiler still showed a lack of caching on CachedIntorspectionResults for the out of the box grails marshaller. This was due to the bad caching implementation in CachedIntrospectionResults. The work around for this was to add the correct class loader to the acceptedClassLoaders in the CachedIntrospectionResults.
public class EnhanceCachedIntrospectionResultsAcceptedClassLoadersListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
CachedIntrospectionResults.acceptClassLoader(Thread.currentThread().getContextClassLoader().getParent());
}
public void contextDestroyed(ServletContextEvent event) {
CachedIntrospectionResults.clearClassLoader(Thread.currentThread().getContextClassLoader().getParent());
Introspector.flushCaches();
}
}
Note that it was required to add the parent to the accepted class loader list rather than the current class loader. Not sure if this is specific to grails or not but this fixed the issue. I'm not sure if there may be a side effect to this fix.
In summary we went from 10 requests/sec in the original setup to 120 requests/sec after using direct reflection and fixing the CachedIntrospectionResults cache.
However the real eye opened was that if we use a 1-1 marshaller per domain class we were seeing another x2 improvement in performance over the generic marshaller where we test objects for whether they're instances of class etc. We're saving a lot of code with the generic marshaller but there's a lot more work to do to get comparable performance to writing a 1-1 marshaller.
Hopefully this will be useful to someone else who runs into this ...
I'm experiencing a discrepancy between the first compilation of a Grails app and the compilation that happens when a file changes while the app is running.
Background:
My app creates some spring beans from Spring LDAP (docs) using conf/spring/resources.groovy.
I have an LdapUser.groovy class in src/groovy (I'm using it similarly to a domain class, except it isn't in grails-app/domain as it doesn't map to a database table).
In BootStrap.groovy I register a JSON marshaller for LdapUser (using JSON.registerObjectMarshaller).
I have a controller with an index method that responds a list of LdapUser objects. This renders correctly in JSON (according to the marshaller).
With that background, here are the pieces of the problem:
When the show method, which responds a single LdapUser, gets called, I get an exception that LdapUser cannot be converted to grails.converters.JSON. (fair enough)
But, if I save the LdapUser.groovy file, thus invoking a recompile on the file while the app is running, the JSON marshaller suddenly works fine.
Before saving the LdapUser.groovy, my controller has a to an LdapUserRepo (a class instantiated via an #EnableLdapRepositories annotation on the controller), but this reference becomes null after I save LdapUser.groovy. I'm not sure how this relates to the problem, as I was also able to reproduce the problem in a controller lacking an injected LdapUserRepo (but with the annotated controllers still in the app).
I also at one point was setting an asType method on the LdapUser class, which was called as expected before the save-invoked recompile. After the recompile, however, my asType method was no longer called and the JSON marshaller was taking over. ( I was doing exception-worthy things in the asType that were throwing before recompile and not throwing after... )
My understanding of the problem is therefore:
Somehow the asType method of the LdapUser.groovy class is not being automatically generated on first compile when running the app, but is being generated on subsequent compiles.
The LdapUser class is tied to the LdapUserRepo in more ways than merely being a type the Repo uses, and the recompile is not reflecting that connection correctly.
Methods rendering lists of objects are somehow unaffected by the asType method. This leads me to believe that the JSON marshaller gets called directly on list elements (instead of via asType) when the list asType has been called (whether or not the "as" operation is implicit...).
My question then is:
what is the Grails compiler doing differently on run-app vs on compile while app is running that could be causing this behavior?
how can I restructure things to ensure it works properly out of the box?
If I need to RTFM, what would be the FM section? (My google-fu is sadly quite weak).
Note: this question is vaguely similar, but doesn't have any meaningfulness to the answer:
Grails: Defining a JSON custom marshaller as static method in domain
I am trying to make a generic connectivity class in my Windows Phone 8 app. This class should be used whenever i need to send a POST request to the service.
In a particular use case i need to call the service, display the response and navigate the user away from the current page.
I am able to successfully achieve the first 2 objectives using the connectivity class. This is because the connectivity class is not part of the UI. So is there a way the GetResponseCallBack method can inform the calling method that it has received the response and then i can navigate the user?
Hope i was able to ask my question clearly.
Thanks!
I have managed to find a work-around for now. Not sure if it is the right way to get the response of the async task. But i am sharing it for the benefit for others who may be facing similar issue.
What i have done is, i have defined the GetResponseCallBack as a public method in the class calling the async task method. Later i pass the same GetResponseCallBack as a parameter to the beginGetResponse method in the GetRequestStreamCallBack method.
This way i am able to bring the control flow back to the phoneApplicationPage after the asyncTask executes, thus allowing me to handle some events on the UI thread.
Hope it helps!
Update: I think is down to a Windsor configuration, does any one have any idea as to what I have not configured correctly with Windsor?
I am currently using Envers within a C# WebApi project. Windsor is used for IoC.
I have a custom RevisionEntity which add a User property to audit the user who has made the data change.
To ensure all configurations were correct I started off with a "simple string here" being added in the NewRevision method;
public class AuditRevisionListener : IRevisionListener
{
public void NewRevision(object revisionEntity)
{
((AuditRevision)revisionEntity).User = "Simple string here";
}
}
and all persisted as expected.
Next step is to achieve a full User object to which I need to obtain the UserService;
public class AuditRevisionListener : IRevisionListener
{
public void NewRevision(object revisionEntity)
{
var userServices = (IUserServices)GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IUserServices));
var user = userServices.GetRequestingUser();
((AuditRevision)revisionEntity).User = user;
}
}
However, the DependencyResolver.GetService is throwing the error;
"Cannot access a disposed object. Object name: 'Scope cache was already disposed. This is most likely a bug in the calling code.'. "
UPDATE
I have now created a demo project available at https://github.com/ScottFindlater/WindsorEnversIssue
On first setting up the solution all will run fine because the custom Envers RevisionListener is not performing any dependency resolving.
Run the solution which performs a GET to the HomeController, which simply loads one User and modifies another;
Dependency resolving is shown to be working as there is an ActionFilter called DependencyResolverDoesWork which successfully resolves the UserServices.
Envers is shown to be working as the UserAudit table is populated.
To “turn on” the dependency resolving in the customer RevisionListener navigate to; Domain NHibernate project, Auditing folder, AuditRevisionListener class, NewRevision method and uncomment the 2 lines of code.
Full rebuild and then run the solution again and the project will run time exception in the WindsorDependencyResolver class, GetService method with “Cannot access a disposed object”, and clicking the View Detail Action expands this message to “{"Cannot access a disposed object.\r\nObject name: 'Scope cache was already disposed. This is most likely a bug in the calling code.'."}”.
The comment posted by Roger, thank you so much, which suggests changing the LifeStyle to Singleton does work. However, this demo has been purposefully kept simple and the use of PerWebRequest LifeStyle is needed because the ApplicationServices in the real project has contextual related data injected such as requesting user which is used to enforce security.
I am so stuck now and any pointers/ answers as to what I have setup wrong will be gratefully received. In addition, I know this has been posted at SO and Envers forum, I WILL update an answer on both.
I think is down to a Windsor configuration, does any one have any idea as to what I have not configured correctly with Windsor?
I haven't tried to run your sample, but I think this is down to an interplay between the two http modules defined in your web.config (https://github.com/ScottFindlater/WindsorEnversIssue/blob/master/API%20Endpoints/Web.config)
Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule - Controls the lifetime of "per web request" components
APIEndpoints.HttpModules.NHibernateSessionCoordinator - Opens a session and begins a transaction at the beginning of each web request, then commits the transaction and disposes the session at the end of the web request
It is at the point where you commit your transaction - at the end of the request, triggered by NHibernateSessionCoordinator, that any changes you've made to objects within your NHibernate ISession actually get written to the database. This is the point at which Envers does its stuff and, in turn, at which you attempt to resolve IUserService from your Windsor container. The exception is thrown because IUserService is registered with the "per web request" lifestyle and Windsor is treating the current web request as complete and has disposed any objects tied to the request.
Have you tried reversing the order in which the HttpModules are defined, e.g. NHibernateSessionCoordinator before PerWebRequestLifestyleModule? This will result in your NHibernate transaction being committed before per web request components are disposed.