I'm trying to work out a way of passing the web current http context to a service class (or initialising the class with a reference to it). I am doing this to abstract the rest of the app away from needing to know anything about the http context.
I also want the service to be testable using TDD, probably using one of the Mockable frameworks. Hence it would be preferable to use an interface rather than an actual class.
An example of what I'd like to achieve:
class WebInstanceService
{
private IHttpContext _Context;
public WebInstanceService( ... , IHttpContext HttpContext )
{
....
_Context = HttpContext;
}
// Methods...
public string GetInstanceVariable(string VariableName)
{
return _Context.Current.Session[VariableName];
}
}
One of the main issues I have is that there is no IHttpContext, the .net http context is a subclass of an abstract class which can't be mocked (easily?).
Another issue is that I can't initialise global instances of the class as then the context won't be relevant for most requests.
I could make the class static, and require the Context to be passed to each function as it is called i.e.
public static string GetInstanceVariable(string VariableName, HttpContext Context)
{ ... }
but this doesn't make the class any easier to test, I still need to create an HttpContext and additionally any non-web-aware services which want to use this class suddenly need to be able to retrieve the Context requiring them to be closely coupled to the web server - the whole reason for wanting to create this class in the first place.
I'm open to ALL suggestions - particularly those which people know facilitate easy tdd testing. How would people suggest I tackle this problem?
Cheers
This is why HttpContextBase and HttpContextWrapper were introduced. You probably want to use HttpContextBase and when passing the real context in, use new HttpContextWrapper( httpContext ), although, I think that what is available to you in the controller is already of type HttpContextBase. I would create one of these in my controller each time rather than trying to reference the current context from the static, global HttpContext.Current instance. If you need it in your view, pass a reference to your strongly typed context in ViewData.
I mock up HttpContextBase frequently in my tests.
class WebInstanceService
{
private HttpContextBase _Context;
public WebInstanceService( ... , HttpContextBase HttpContext )
{
....
_Context = HttpContext;
}
// Methods...
public string GetInstanceVariable(string VariableName)
{
return _Context.Session[VariableName];
}
}
What we do is spin one of these up http://haacked.com/archive/2007/06/19/unit-tests-web-code-without-a-web-server-using-httpsimulator.aspx
Easy as pie, just instanciate an HttpSimulator and fill in the values, and HttpContext.Current gets filled up with whatever you specify.
IHttpContext is something that is in MVC, and aparently one day will be in webforms. Hopefully that day will be .net 4
ASP.NET comes with System.Web.Abstractions that include HttpContextBase that you can use for dealing with the HttpContext in a testing situation.
I would personally abstract away the direct dependency on the HttpContext.
Related
I'm new to C#, and when i opened the Controller of a MVC project(ASP.NET), i have found the following syntax:
public class CategoriasController : Controller
{
private readonly ApplicationDbContext _context;
public CategoriasController(ApplicationDbContext context)
{
_context = context;
}
I'm sorry to ask, but what's happening on line 3?
private readonly ApplicationDbContext _context;
Is _context a variable? An object? That's the same of saying _context = new ApplicationDbContext?
Sorry for the question, I've searched the Microsoft docs, but couldn't find any answer.
The MVC model as a whole when implemented in C# is a little interesting, but does work very well.
When a request is made, the path of the request is used by the routing mechanism to use reflection to instantiate a class capable of handling the response.
In this case, when a matching ActionResult method name matching the CategoriasController class name, for example /Categorias/Fiction is used, then the matching controller class will be instantiated via reflection.
Once the class is instantiated, the method is called. During class instantiation, normal things occur that occur with any other class. So, what you see here, is the availability of a class level member _context. Looking further, you can see that there is a constructor which can be called with a context as well. That is known as inversion of control, and is accomplished with a dependency injection container. This means that during the instantiation from reflection, a fully instantiated context (for querying a database) is also created and then passed in. In MVC the DI container is often defined in the global.asax.cs file.
Once the class is instantiated, and the member method called, the return view essentially creates a string writer to be written to the response stream, and MVC's job is done.
This ensures that the class level variable _context can only be set in the constructor and cannot otherwise be changed. In the context of accessing a database as here you do not want the class methods to be able to change this, only to use.
The the c# documentation for readonly here it states "In a field declaration, readonly indicates that assignment to the field can only occur as part of the declaration or in a constructor in the same class."
I would like to pass global custom data from API Level to Application Service, to Repository and DB Context layer, without using parameters in every method.
1) One method is HttpContextAccessor.
Curious if there is any other global parameter embedded in Net Core, or is this the only known strategy? We are passing auditable data, CreateBy, ModifiedDate, but may extend it other properties. We have 100+ apis, application methods, repositories, and trying to prevent passing around a parameter.
_httpContextAccessor.HttpContext.Items["TestKey"] = "SampleData";
DBContext:
public class AuditableDbContext: DbContext
{
private readonly IHttpContextAccessor _httpContextAccessor;
public AuditableDbContext(DbContextOptions<AuditableDbContext> options, IHttpContextAccessor httpContextAccessor)
: base(options)
{
_httpContextAccessor = httpContextAccessor;
}
Custom Data changes based on application behavior and user interaction.
One problem with using context aware objects across multiple layers is the dependency to that context.
It makes it really hard to understand the code in the long run, and, most importantly, it makes it harder to unit test.
Imagine you rely on an HttpContext item coming from your controller in another layer. The unit test of that layer would now have to mimic the controller and set the item on the context to produce a proper state.
Having multiple parameters getting passed around everywhere is bad, too, true.
One way of solving it would be a simple Poco object to store the state and pass that around, that would make unit testing simple and also reduce the number of parameters of methods in all layers.
public class RequestState
{
public User CreateBy { get; }
...
}
The controller would initiate the state object and all layers would use it...
Another way would be to rely on the DI framework and use a scoped lifetime object which gets injected into all layers which you then can abuse to store your state information.
That's pretty similar to http context but at least its your own thing and you can do whatever you want with it and also add strongly typed properties instead of an Items collection.
In your startup, you'd inject the scope object with Scoped lifetime.
You inject the object into your controller and all other classes (works only if those classes are also scoped or transient).
I'm building a OWIN Self-Hosted Web API 2 application and I'm using a generic repository pattern and using Autofac for dependency injection.
My generic repository class;
public abstract class Repository<T> : IRepository<T> where T : BaseEntity
{
private DbContext context_;
private Identity _currentUser; //This needs to be resolved
public Repository(DbContext context)
{
context_ = context;
}
public T Update(T item)
{
//item.ModifiedBy = _currentUser.UserName; // The value needs to be assigned
context_.SaveChanges();
return item;
}
}
Problem:
I need to access the current user and I need to update the database with ModifiedBy field.
I'm trying to avoid constructor injection, as the repository object is created in several places in project by passing DbContext as a constructor argument.
Is there any alternative ways to do this without modifying existing code much.
Could anyone help me to achieve my requirement.
Note:
Alternatively I can override the SaveChanges() method in DbContext class.
But again I cannot access the current there.
Identity is accessed from Thread.CurrentPrincipal.Identity, there is no problem setting this to whatever in a test setup eg. Thread.CurrentPrincipal = new ClaimsPrincipal(identity);
Edited
Yes CurrentPrincipal is safe to use, you would normally create some utilities functions to read out the values you need. Or you could of course create your own abstraction, and inject that to your classes, but I don't see the point of that.
btw. generic repositories are never a wise choice (read up on DDD).
I have a asp.net mvc app where a lot of things are dependent on knowing the url of the web request (it's multi-tenant). Currently the HttpContext is being injected in a lot of constructors (through a wrapper that sets up some variables based on the context) using Simple Injector. This means that most things have to be instanced "per web request" vs per application.
Now what I could do here is just pass the HttpContext wrapper, or only the required data, in methods rather that constructor injection.
What I would like some clue on is the actual performance difference. Because it does make it a lot less elegant having to always pass the wrapper/data. This is however a quite high-traffic site so I will definitely consider changing it up.
I do realize this depends a bit on what's going on in the constructor, but assume that all it does is assign dependencies.
To clarify I do not have a specific performance problem. This is only optimization and I'm wondering if it's worth going through the work of refactoring to achieve this.
Instead of just a wrapper you can place a provider in between, which you could be singleton, which makes it possible for all consumers to be singleton as well.
Like this:
public interface IHttpContextProvider
{
HttpContext CurrentContext { get; }
}
public class HttpContextProvider : IHttpContextProvider
{
public HttpContext CurrentContext => HttpContext.Current;
}
public interface IMyContextWrapper
{
string CurrentRoute { get; }
}
public class MyContextWrapper : IMyContextWrapper
{
private readonly IHttpContextProvider httpContextProvider;
public MyContextWrapper(IHttpContextProvider httpContextProvider)
{
this.httpContextProvider = httpContextProvider;
}
public string CurrentRoute
{
get
{
var context = this.httpContextProvider.CurrentContext;
return informationFromContext;
}
}
}
I'd be tempted to stick with constructor injection because it clearly shows the dependency. It's true that there could be a small performance hit because you have to use per-web-request, and that will involve more garbage collection than if you pass the context as a parameter. But, has it yet become a problem?
If you find this is a performance problem, you could look at a third option providing your tenant count is not enormous. You could instantiate and re-use a pool of singleton classes, where one is configured per tenant.
I've built a multi-tenant site and have certain services that need to be created for every web request, and definitely haven't had performance problems in that area.
I have a service layer, which has a range of methods. These methods have implemented caching, like the following:
string key = "GetCategories";
if (CacheHandler.IsCachingEnabled() && !CacheHandler.ContainsKey(key))
{
var categories = RequestHelper.MakeRequest("get_category_index")["categories"];
var converted = categories.ToObject<List<Category>>();
CacheHandler.InsertToCache(key,converted);
return converted;
}
return CacheHandler.GetCache(key) as List<Category>;
Now, problem is I also want to make a unit test, like the following:
[TestMethod]
public void GetCategories()
{
IContentService contentService = new ContentService();
var resp = contentService.GetCategories();
Assert.IsNotNull(resp,"Should not be null");
}
Problem is, that the HttpContext.Current inside my CacheHandler is null during the unit test (obviously).
What is the easiest way to fix this?
(Please be as specific as possible because I haven't done a lot of unit testing before)
This screams dependency injection. The main problem I see is that you access the CacheHandler statically, so in a unit test, you:
a) cannot test the service without "testing" the CacheHandler as well
b) cannot supply any other CacheHandler to the service, for example a mocked one
If that's possible in your case, I'd either refactor or at least wrap the CacheHandler so that the service accesses an instance of it. In a unit test, you can then supply the service with a "fake" CacheHandler, that would not access HttpContext and also could give you a very fine control over the test itself (e.g. you can test what happens when an item is cached vs. when it isn't in two absolutely independent unit tests)
For the mocking part, I suppose it's easiest to create an interface and then use some automocking/proxy-generation framework designed for testing, for example Rhino Mocks (but there are many more, it just happens that I'm using this one and am very happy with it :)). Another approach (easier for a beginner, but more cumbersome in an actual development) would be simply to design the CacheHandler (or its wrapper) so that you can inherit from it and override the behaviour yourself.
Finally for the injection itself, I have found out a handy "pattern", which takes advantage of C# default method arguments and the standard constructor injection. The service constructor would look like:
public ContentService(ICacheHandler cacheHandler = null)
{
// Suppose I have a field of type ICacheHandler to store the handler
_cacheHandler = cacheHandler ?? new CacheHandler(...);
}
So in the application itself, I can call the constructor without parameters (or let frameworks construct the service, if it's ASP.NET handler, WCF service or some other kind of class) and in unit tests, I can supply whatever is implementing the said interface.
In case of Rhino Mocks, it can look like this:
var mockCacheHandler = MockRepository.GenerateMock<ICacheHandler>();
// Here I can mock/stub methods and properties, set expectations etc...
var sut = new ContentService(mockCacheHandler);
Dependency Injection as recommended in Honza Brestan's answer is certainly a valid solution, and maybe the best solution - especially if you might want to use something other than the ASP.NET Cache in the future.
However I should point out that you can use the ASP.NET Cache without needing an HttpContext. Instead of referencing it as HttpContext.Current.Cache, you can use the static property HttpRuntime.Cache.
This will enable you to use the Cache outside the context of an HTTP request, such as in a unit test or in a background worker thread. In fact I'd generally recommend using HttpRuntime.Cache for data caching in the business tier to avoid taking the dependency on the existence of an HttpContext.
Separate the cache into its own class, working like a proxy.
public interface IContentService
{
Categories GetCategories();
}
public class CachingContentService : IContentService
{
private readonly IContentService _inner;
public CachingContentSerice(IContentService _inner)
{
_inner = inner;
}
public Categories GetCategories()
{
string key = "GetCategories";
if (!CacheHandler.ContainsKey(key))
{
Catogories categories = _inner.GetCategories();
CacheHandler.InsertToCache(key, categories);
}
return CacheHandler.GetCache(key);
}
}
public class ContentSerice : IContentService
{
public Categories GetCategories()
{
return RequestHelper.MakeRequest("get_category_index")["categories"];
}
}
To enable caching, decorate the real ContentService with the cache:
var service = new CachingContentService(new ContentService());
To test the cache, create the CachingContentService with a test double as a constructor parameter. Use the test double to verify the cache: call it once and it should call the service behind. Call it twice and it should not call the service behind.
As a best practice, you only want to test one thing during a test and what you're describing has multiple steps. Therefore, it would be best to construct your test of your "RequestHelper.MakeRequest" and other routines so that they run their tests separately from the caching scenario. Testing them separately will let you know if their are problems in these routines or in the caching. You can integrate them later to test them as a group.
To test the caching separately, you can create a mock object to create the HttpContext with the properties that you need. Here are some previous answers that should help you put this together:
How do I mock the HttpContext in ASP.NET MVC using Moq?
Mock HttpContext.Current in Test Init Method