I have an ASP.NET MVC 3 (Razor) Web Application, with a particular page which is highly database intensive, and user experience is of the upmost priority.
Thus, i am introducing caching on this particular page.
I'm trying to figure out a way to implement this caching pattern whilst keeping my controller thin, like it currently is without caching:
public PartialViewResult GetLocationStuff(SearchPreferences searchPreferences)
{
var results = _locationService.FindStuffByCriteria(searchPreferences);
return PartialView("SearchResults", results);
}
As you can see, the controller is very thin, as it should be. It doesn't care about how/where it is getting it's info from - that is the job of the service.
A couple of notes on the flow of control:
Controllers get DI'ed a particular Service, depending on it's area. In this example, this controller get's a LocationService
Services call through to an IQueryable<T> Repository and materialize results into T or ICollection<T>.
How i want to implement caching:
I can't use Output Caching - for a few reasons. First of all, this action method is invoked from the client-side (jQuery/AJAX), via [HttpPost], which according to HTTP standards should not be cached as a request. Secondly, i don't want to cache purely based on the HTTP request arguments - the cache logic is a lot more complicated than that - there is actually two-level caching going on.
As i hint to above, i need to use regular data-caching, e.g Cache["somekey"] = someObj;.
I don't want to implement a generic caching mechanism where all calls via the service go through the cache first - i only want caching on this particular action method.
First thought's would tell me to create another service (which inherits LocationService), and provide the caching workflow there (check cache first, if not there call db, add to cache, return result).
That has two problems:
The services are basic Class Libraries - no references to anything extra. I would need to add a reference to System.Web here.
I would have to access the HTTP Context outside of the web application, which is considered bad practice, not only for testability, but in general - right?
I also thought about using the Models folder in the Web Application (which i currently use only for ViewModels), but having a cache service in a models folder just doesn't sound right.
So - any ideas? Is there a MVC-specific thing (like Action Filter's, for example) i can use here?
General advice/tips would be greatly appreciated.
An action attribute seems like a good way to achieve this. Here's an example (disclaimer: I am writing this from the top of my head: I've consumed a certain quantity of beer when writing this so make sure you test it extensively :-)):
public class CacheModelAttribute : ActionFilterAttribute
{
private readonly string[] _paramNames;
public CacheModelAttribute(params string[] paramNames)
{
// The request parameter names that will be used
// to constitute the cache key.
_paramNames = paramNames;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
var cache = filterContext.HttpContext.Cache;
var model = cache[GetCacheKey(filterContext.HttpContext)];
if (model != null)
{
// If the cache contains a model, fetch this model
// from the cache and short-circuit the execution of the action
// to avoid hitting the repository
var result = new ViewResult
{
ViewData = new ViewDataDictionary(model)
};
filterContext.Result = result;
}
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
base.OnResultExecuted(filterContext);
var result = filterContext.Result as ViewResultBase;
var cacheKey = GetCacheKey(filterContext.HttpContext);
var cache = filterContext.HttpContext.Cache;
if (result != null && result.Model != null && cache[key] == null)
{
// If the action returned some model,
// store this model into the cache
cache[key] = result.Model;
}
}
private string GetCacheKey(HttpContextBase context)
{
// Use the request values of the parameter names passed
// in the attribute to calculate the cache key.
// This function could be adapted based on the requirements.
return string.Join(
"_",
(_paramNames ?? Enumerable.Empty<string>())
.Select(pn => (context.Request[pn] ?? string.Empty).ToString())
.ToArray()
);
}
}
And then your controller action could look like this:
[CacheModel("id", "name")]
public PartialViewResult GetLocationStuff(SearchPreferences searchPreferences)
{
var results = _locationService.FindStuffByCriteria(searchPreferences);
return View(results);
}
And as far as your problem with referencing the System.Web assembly in the service layer is concerned, that's no longer a problem in .NET 4.0. There's a completely new assembly which provides extensible caching features : System.Runtime.Caching, so you could use this to implement caching in your service layer directly.
Or even better if you are using an ORM at your service layer probably this ORM provides caching capabilities? I hope it does. For example NHibernate provides a second level cache.
I will provide general advices and hopefully they will point you to the right direction.
If this is your first stab at caching in your application, then don't cache HTTP response, cache the application data instead. Usually, you start with caching data and giving your database some breathing room; then, if it's not enough and your app/web servers are under huge stress, you can think of caching HTTP responses.
Treat your data cache layer as another Model in MVC paradigm with the all subsequent implications.
Whatever you do, don't write your own cache. It always looks easier than it really is. Use something like memcached.
My answer is based on the assumption that your services implement an interface, for example the type of _locationService is actually ILocationService but is injected with a concrete LocationService. Create a CachingLocationService that implements the ILocationService interface and change your container configuration to inject that caching version of the service to this controller. The CachingLocationService would itself have a dependecy on ILocationService which would be injected with the original LocationService class. It would use this to execute the real business logic and concern itself only with pulling and pushing from cache.
You don't need to create CachingLocationService in the same assembly as the original LocationService. It could be in your web assembly. However, personally I'd put it in the original assembly and add the new reference.
As for adding a dependency on HttpContext; you can remove this by taking a dependency on
Func<HttpContextBase>
and injecting this at runtime with something like
() => HttpContext.Current
Then in your tests you can mock HttpContextBase, but you may have trouble mocking the Cache object without using something like TypeMock.
Edit: On further reading up on the .NET 4 System.Runtime.Caching namespace, your CachingLocationService should take a dependency on ObjectCache. This is the abstract base class for cache implementations. You could then inject that with System.Runtime.Caching.MemoryCache.Default, for instance.
It sounds like you're trying to cache the data you are getting from your database. Here's how I handle this (an approach that I've seen used in many open-source MVC projects):
/// <summary>
/// remove a cached object from the HttpRuntime.Cache
/// </summary>
public static void RemoveCachedObject(string key)
{
HttpRuntime.Cache.Remove(key);
}
/// <summary>
/// retrieve an object from the HttpRuntime.Cache
/// </summary>
public static object GetCachedObject(string key)
{
return HttpRuntime.Cache[key];
}
/// <summary>
/// add an object to the HttpRuntime.Cache with an absolute expiration time
/// </summary>
public static void SetCachedObject(string key, object o, int durationSecs)
{
HttpRuntime.Cache.Add(
key,
o,
null,
DateTime.Now.AddSeconds(durationSecs),
Cache.NoSlidingExpiration,
CacheItemPriority.High,
null);
}
/// <summary>
/// add an object to the HttpRuntime.Cache with a sliding expiration time. sliding means the expiration timer is reset each time the object is accessed, so it expires 20 minutes, for example, after it is last accessed.
/// </summary>
public static void SetCachedObjectSliding(string key, object o, int slidingSecs)
{
HttpRuntime.Cache.Add(
key,
o,
null,
Cache.NoAbsoluteExpiration,
new TimeSpan(0, 0, slidingSecs),
CacheItemPriority.High,
null);
}
/// <summary>
/// add a non-removable, non-expiring object to the HttpRuntime.Cache
/// </summary>
public static void SetCachedObjectPermanent(string key, object o)
{
HttpRuntime.Cache.Remove(key);
HttpRuntime.Cache.Add(
key,
o,
null,
Cache.NoAbsoluteExpiration,
Cache.NoSlidingExpiration,
CacheItemPriority.NotRemovable,
null);
}
I have those methods in a static class named Current.cs. Here's how you can apply those methods to your controller action:
public PartialViewResult GetLocationStuff(SearchPreferences searchPreferences)
{
var prefs = (object)searchPreferences;
var cachedObject = Current.GetCachedObject(prefs); // check cache
if(cachedObject != null) return PartialView("SearchResults", cachedObject);
var results = _locationService.FindStuffByCriteria(searchPreferences);
Current.SetCachedObject(prefs, results, 60); // add to cache for 60 seconds
return PartialView("SearchResults", results);
}
I've accepted #Josh's answer, but thought i'd add my own answer, because i didn't exactly go with what he suggested (close), so thought for completeness i'd add what i actually did.
The key is i am now using System.Runtime.Caching. Because this exists in an assembly which is .NET specific and not ASP.NET specific, i have no problems referencing this in my service.
So all i've done is put the caching logic in the specific service layer methods that need the caching.
And an important point, im working off System.Runtime.Caching.ObjectCache class - this is what get's injected into the constructor of the service.
My current DI injects a System.Runtime.Caching.MemoryCache object. The good thing about the ObjectCache class is that it is abstract and all the core methods are virtual.
Which means for my unit tests, i have created a MockCache class, overriding all methods and implementing the underlying cache mechanism with a simple Dictionary<TKey,TValue>.
We plan to switch over to Velocity soon - so again, all i need to do is create another ObjectCache deriving class and i'm good to go.
Thanks for the help everyone!
Related
I use .NET Core WebAPI with dependency injection and multiple authentication schemas (http basic, access keys, JWT). I inject some business services which require some authenticated user data. If user is authenticated by any of auth middleware, DI works fine. If the user is not authenticated, DI cannot resolve some services. I need DI to return null.
How is that possible? Code bellow will result in exception, null is not allowed as result.
services.AddTransient<IMasterRepository>(serviceProvider =>
{
var _serviceFactory = new RepositoriesFactory(Configuration);
if (!Authenticated)
{
return null;
}
return _serviceFactory.CreateMasterRepository();
});
Also, I cannot return 401 in auth middleware, because another middleware may success (expl: cannot return 401 in http basic auth middleware because next one, JWT, may success)
Also, I cannot add "authentication required" check after all auth middlewares because some controllers are public (no authentication / dependency injection required).
Any advice?
Thanks!
There's no problem in registering an implementation as null. It's only in resolving that you will have a problem.
In other words, if you register:
services.AddTransient<IMasterRepository>(provider => null);
And then try:
private readonly IMasterRepository _repository;
public SomeController(IMasterRepository repository)
{
_repository = repository;
}
You will get an InvalidOperationException at runtime, with a message similar to:
Unable to resolve service for type 'MyApp.IMasterRepository' while attempting to activate 'MyApp.Controllers.SomeController'
However, there is a simple workaround. Rather than injecting the interface, inject an IEnumerable of that interface:
private readonly IMasterRepository _repository;
public SomeController(IEnumerable<IMasterRepository> repositories)
{
_repository = repositories.First(); // (using System.Linq)
}
You might think it should be FirstOrDefault, however there will indeed be a single item containing the null you registered.
This approach works because DI in ASP.Net Core supports registering multiple implementations of a given type and doesn't distinguish between null and object instances at time of registration.
Do keep in mind that even though this works, it's not recommended because now the _repository variable is potentially nullable, and a null check must be used every time it is accessed. For example: if (_repository != null) { _repository.DoSomething(); } or _repository?.DoSomething();. Most people do not expect to write code like that.
This covers the DI part of the question. But if indeed the issue is strictly with auth then ste-fu's answer describes a more appropriate approach.
The default DI framework does not allow for the factory delegate to return null by design.
Consider null object pattern by creating a NullObject derived from the interface
public class NullRepository : IMasterRepository {
public static readonly IMasterRepository Empty = new NullRepository();
public NullRepository () { }
//...implement members that do nothing and may return empty collections.
}
that does nothing when invoked.
services.AddTransient<IMasterRepository>(serviceProvider => {
IMasterRepository result = NullRepository.Empty;
var _serviceFactory = new RepositoriesFactory(Configuration);
if (Authenticated) {
result = _serviceFactory.CreateMasterRepository();
}
return result;
});
Checking for null now becomes
//ctor
public SomeClass(IMasterRepository repository) {
if(repository == NullRepository.Empty)
//...throw
//...
}
To my mind, this sounds like a problem with your dependency setup.
All your auth Middleware should be setting the ClaimsPrincipal on the HttpContext as part of the Invoke method if the authentication is successful.
Whilst a service may need to be able to access the ClaimsPrincipal in order to function correctly, you can do this by injecting IHttpContextAccessor in the constructor and enabling it in the ConfigureServices method in Startup.cs.
Getting the DI container to return null would just mean that you have to make lots of null checks all over your code. Ensuring that the ClaimsPrincipal is correctly set means that you can leverage the [Authorize] attribute to control access to particular Controllers or methods or setup Policy-based authorization which should return the correct status codes after all the auth middleware has run.
While you could create a wrapper class that is able to hold the service instance or null -OR- you could inject a dummy service in case the user is not authenticated, it's not recommended from a clean-code perspective. Both solutions would be a code smell as for the first: you would have to place null checks everywhere, even in places where you'd expect the service. And the latter: it seems like the code could actually use the service, but it's not clear a dummy service will be provided.
To keep your code clean, I'd just move the public routes, that are not requiring those services, to a separate controller class (with the same route as they have now) that does not depend on the service. This way, you can just register the repository as-is and avoid magic trickery.
I have a member of my controller
private Lazy<MyCache> loadedComponentCache = new Lazy<MyCache>(() =>
{
MyCache instance = MyCacheb.Instance;
instance.LoadStuffAsync().Wait();
return instance;
}, LazyThreadSafetyMode.PublicationOnly);
that I'm using to lazy-call a long-running method LoadAsync() that will only need called if a certain API endpoint is hit after the user goes to the page.
[HttpGet]
public ActionResult GetStuff()
{
var results = from component in loadedComponentCache.Value.All()
// ...
}
Any idea why it's re-loading every time the API endpoint is hit? My understanding is that an instance of my controller is created only when the user goes to the page and thus this will only be hit once per API call per user visiting the page.
You could make loadedComponentCache static but that's not ideal. If you are using an IoC container you could register it as a singleton. These long lived objects are generally to be avoided though if possible.
If you you truely need this long lived cache then you should probably consider using something like Redis which is designed and optimised for this sort of scenario and can be distributed across multiple nodes. https://redis.io/topics/introduction
I'm in a situation where the classic functionality of vnext's DI container is not enough to provide me with the correct functionality. Let's say I have a DataService that gets data from a database like this:
public class DataService : IDataService, IDisposable {
public List<MyObject> GetMyObjects()
{
// do something to fetch the data...
return myObjects;
}
}
I can then register this service in the DI container during the configuration phase in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped(typeof(IDataService), typeof(DataService));
}
This ensures the correct lifecylce of the service (one per request scope), however, I need the service to access a different database when a different request is made. For simplicity reasons, let's say the following scenario applies:
when a request to my Web API is made, the DataService will access the currently logged in user, which contains a claim called Database which contains the information which database to use.
the DataService is then instantiated with the correct database connection.
In order to get the second step to work, I have created a constructor for the DataService like this:
public DataService(IHttpContextAccessor accessor)
{
// get the information from HttpContext
var currentUser = accessor.HttpContext.User;
var databaseClaim = currentUser.Claims.SingleOrDefault(c => c.Type.Equals("Database"));
if (databaseClaim != null)
{
var databaseId = databaseClaim.Value;
// and use this information to create the correct database connection
this.database = new Database(databaseId);
}
}
By using the currently logged in user and his claims, I can ensure that my own authentication middleware takes care of providing the necessary information to prevent attackers from trying to access the wrong database.
Of course adding the IDisposable implementation is required to cleanup any database connections (and gets called correctly using the scope lifecycle).
I can then inject the DataService into a controller like this
public MyController : Controller
{
private IDataService dataService;
public MyController(IDataService dataService)
{
this.dataService = dataService;
}
}
This all works fine so far.
My questions now are:
Is there another way to create the instance other than using the constructor of the DataService? Maybe accessing the object the IServiceCollection provides in a different place other than during the configration phase which runs only once? Maybe using my own OWIN middleware?
Is this method really safe? Could two requests made at the same time accidentally end up with the DataServiceintended for the other request and therefore end up giving out the wrong data?
What you have is fine.
Is there another way to create the instance other than using the constructor of the DataService? Maybe accessing the object the IServiceCollection provides in a different place other than during the configration phase which runs only once? Maybe using my own OWIN middleware?
Not really. You can use delegate registration but it's the same problem.
Is this method really safe?
Yes
Could two requests made at the same time accidentally end up with the DataServiceintended for the other request and therefore end up giving out the wrong data?
Nope. The IHttpContextAcessor uses AsyncLocal (http://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html) to provide access to the "current" http context.
I have created a WCF service which reads from a database and sends back results. For performance reasons I'd like to cache the tables on service startup (which happens in a windows service OnStart). But there's no such thing as constructors in WCF (right?) so best thing I came up with is create an Init() function and call that like the following:
protected override void OnStart(string[] args)
{
mServiceHost = new ServiceHost(typeof(DLSService.DLSService), new Uri("http://localhost:8000/DLS"));
mServiceHost.AddServiceEndpoint(typeof(DLSService.IDLSService), new BasicHttpBinding(), "ServicesHost");
((DLSService.DLSService)mServiceHost.SingletonInstance).Init();
mServiceHost.Open();
}
But using SingletonInstance and casting to the correct type does not seem all that elegeant to me.
Are there more elegant ways to achieve constructor like functionality in WCF?
The recommended best practice is to use the per-call activation model in WCF and keep the services totally stateless.
This means: every time the client makes a request, on the server-side, an instance of your service implementation class will be created, the requested service call will be made, and then the service class will be destroyed again.
So putting your initialization code into the service implementation class constructor would be a really bad idea - it would be executed for each and every single request.
What you could do is have some kind of logic (either in your service class, or some support code, e.g. some kind of an admin interface) that would load those tables you want to cache into a persistent cache, e.g. something like the AppFabric cache. Once done, multiple service instances handling requests could use that common cache to get better performance.
This can be solved with a memoization library, like MbCache. We are doing exactly what you are looking for; on application start-up we call each service operation that we want to cache, and MbCache caches the result for consecutive calls (i.e. no database round-trip to get results) until the cache expires.
MbCache does come with its on fair share of complexity, but once it is running it works very well and handles all the cache logic for us.
You can use the IInstanceProvider interface to create your service, read this article for more information.
Here's an example of code:
public class CustomInstanceProvider:IInstanceProvider
{
public object GetInstance(InstanceContext instanceContext)
{
return GetInstance(instanceContext, null);
}
public object GetInstance(InstanceContext instanceContext, System.ServiceModel.Channels.Message message)
{
return new DLSService.DLSService();
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
}
}
var mServiceHost = new ServiceHost(typeof(DLSService.DLSService), new Uri("http://localhost:8000/DLS"));
mServiceHost.AddServiceEndpoint(typeof(DLSService.IDLSService), new BasicHttpBinding(), "ServicesHost");
foreach (var channelDispatcher in mServiceHost.ChannelDispatchers.OfType<ChannelDispatcher>())
{
foreach (var endpointDispatcher in channelDispatcher.Endpoints)
{
endpointDispatcher.DispatchRuntime.InstanceProvider = new CustomInstanceProvider();
}
}
mServiceHost.Open();
With framework 4.5 you can use a configuration's function in your service implementation code:
http://msdn.microsoft.com/en-us/library/hh205277(v=vs.110).aspx.
I was asked to implement castle dynamic proxy in my asp.net web application and i was going through couple of articles which i got from Castle Project and Code Project about castle dynamic proxy in asp.net web application....
Both articles delt with creating interceptors but i can't get the idea why interceptors are used with classes.... Why should i intercept my class which is behaving properly?
Let's say that your class needs to do 3 things for a certain operation:
Perform a security check;
Log the method call;
Cache the result.
Let's further assume that your class doesn't know anything about the specific way you've configured your security, logging, or caching. You need to depend on abstractions of these things.
There are a few ways to go about it. One way would be to set up a bunch of interfaces and use constructor injection:
public class OrderService : IOrderService
{
private readonly IAuthorizationService auth;
private readonly ILogger logger;
private readonly ICache cache;
public OrderService(IAuthorizationService auth, ILogger logger,
ICache cache)
{
if (auth == null)
throw new ArgumentNullException("auth");
if (logger == null)
throw new ArgumentNullException("logger");
if (cache == null)
throw new ArgumentNullException("cache");
this.auth = auth;
this.logger = logger;
this.cache = cache;
}
public Order GetOrder(int orderID)
{
auth.AssertPermission("GetOrder");
logger.LogInfo("GetOrder:{0}", orderID);
string cacheKey = string.Format("GetOrder-{0}", orderID);
if (cache.Contains(cacheKey))
return (Order)cache[cacheKey];
Order order = LookupOrderInDatabase(orderID);
cache[cacheKey] = order;
return order;
}
}
This isn't horrible code, but think of the problems we're introducing:
The OrderService class can't function without all three dependencies. If we want to make it so it can, we need to start peppering the code with null checks everywhere.
We're writing a ton of extra code to perform a relatively simple operation (looking up an order).
All this boilerplate code has to be repeated in every method, making for a very large, ugly, bug-prone implementation.
Here's a class which is much easier to maintain:
public class OrderService : IOrderService
{
[Authorize]
[Log]
[Cache("GetOrder-{0}")]
public virtual Order GetOrder(int orderID)
{
return LookupOrderInDatabase(orderID);
}
}
In Aspect Oriented Programming, these attributes are called Join Points, the complete set of which is called a Point Cut.
Instead of actually writing dependency code, over and over again, we leave "hints" that some additional operations are supposed to be performed for this method.
Of course, these attributes have to get turned into code sometime, but you can defer that all the way up to your main application code, by creating a proxy for the OrderService (note that the GetOrder method has been made virtual because it needs to be overridden for the service), and intercepting the GetOrder method.
Writing the interceptor might be as simple as this:
public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
if (Attribute.IsDefined(invocation.Method, typeof(LogAttribute))
{
Console.Writeline("Method called: "+ invocation.Method.Name);
}
invocation.Proceed();
}
}
And creating the proxy would be:
var generator = new ProxyGenerator();
var orderService = (IOrderService)generator.CreateClassProxy(typeof(OrderService),
new LoggingInterceptor());
This is not only a lot less repetitive code, but it completely removes the actual dependency, because look what we've done - we don't even have an authorization or caching system yet, but the system still runs. We can just insert the authorization and caching logic later by registering another interceptor and checking for AuthorizeAttribute or CacheAttribute.
Hopefully this explains the "why."
Sidebar: As Krzysztof Koźmic comments, it's not a DP "best practice" to use a dynamic interceptor like this. In production code, you don't want to have the interceptor running for unnecessary methods, so use an IInterceptorSelector instead.
The reason you would use Castle-DynamicProxy is for what's called Aspect Orientated Programming. It lets you interject code into the standard operation flow of your code without the need to become dependent on the code itself.
A simple example is as always, logging. That you would create a DynamicProxy around a class that you have errors from that it logs the data going into the method and catches any exceptions and then logs the exception.
Using the intercepter your current code has no idea it exists (assuming you have your software built in a decoupled way with interfaces correctly) and you can change the registration of your classes with an inversion of control container to use the proxied class instead without having to change a single line else where in code. Then when you solve the bug you can turn off the proxying.
More advanced usage of proxying can be seen with NHibernate where all of the lazy loading is handled through proxies.