StructureMap dynamic set properties per HttpRequest - structuremap

StructureMap Configuration
Is there a way in SM to dynamically inject property value only for the duration of a request then set the those property back to default after the request is completed?
I'm specifically referring in the HttpRequest context.
I have a IDBAccessor interface and a DBAccessor concrete implementation.
IDBAccessor has a public property for connection string.
I want to set the connectionstring dynamically for each HttpRequest depending on some parameter that is passed in.
Is there an easy to accomplish this?
Thanks for the input.

I assume you have a class that encapsulates the logic to determine the connection string for each request. I'll call it ConnectionStringSource. You could then configure StructureMap like this:
ObjectFactory.Initialize(x =>
{
x.For<IDBAccessor>().HybridHttpOrThreadLocalScoped()
.Use(ctx =>
{
var connectionString = ctx.GetInstance<ConnectionStringSource>().GetConnectionString();
var dbAccessor = new DBAccessor {ConnectionString = connectionString};
return dbAccessor;
});
});
public class ConnectionStringSource
{
public string GetConnectionString()
{
// determine the connection string somehow
return "connection string";
}
}
The HybridHttpOrThreadLocalScoped call will make sure you get a new instance of DBAccessor for each HTTP request. And by using the Func<> overload of Use(), you can execute the code to determine and set the connection string during each request.
Note: You might want to just make the connection string a constructor parameter of DBAccessor instead of making it a property on the interface.

Related

C# Web Api 2 use StructureMap to pass request data into injected dependency constructor parameter

I'm getting my feet wet with C# IoC frameworks. I chose StructureMap.Webapi2 to integrate into an existing api.
I have the following scenario which I am not sure what the best way to implement is.
public class MyController : ApiController
{
public IHttpActionResult MyAction(string clientCode, [FromBody]MyDto bodyData)
{
var client = new ClientManager().GetClientByCode(clientCode);
var someData = new SomeData
{
User = bodyData.User,
ClientCode = clientCode,
SomeField = client.SomeField
};
var myService = new WorkerService(someData);
myService.DoSomething();
return Ok();
}
}
A peek a the WorkerService:
public WorkerService(SomeData someData)
{
_someData = someData;
_someCollection = GetSomeData(); // GetSomeData uses _someData
}
public DoSomething()
{
// some code that uses _someData and _someCollection
}
Approach 1:
Make WorkerService's constructor parameterless and add a public SomeData property that can be initialized inside MyController MyAction.
Then both ClientManager and WorkerService can be injected by the IoC into a constructor to be added to the controller.
The Action would then look like:
public IHttpActionResult MyAction(string clientCode, [FromBody]MyDto bodyData)
{
var client = _clientManager.GetClientByCode(clientCode);
var someData = new SomeData
{
User = bodyData.User,
ClientCode = clientCode,
SomeField = client.SomeField
};
_myService.SomeData = someData;
_myService.DoSomething();
return Ok();
}
Approach 2 (the one I'm not sure how to implement)
Keep WorkerService constructor as is (with a parameter). Inject the service into the Controller's constructor (requires building and pass the service's argument (SomeData) at runtime, instead of having the MyAction build SomeData).
Somehow build SomeData (maybe using a factory) before for each request is handled by the controller. This would mean that ClientManager would have to be injected to that somehow/factory. The output of the somehow/factory would be used by the IoC when building the WorkerService to be injected into the controller, per request.
To me, Approach 1 seems quicker and simple, but Approach 2 seems to be more attractive, more challenging and with more learnings.
I ended up finding a solution for the problem:
Create a passive attribute and add to the action
Create an ActionFilter, which checks for the attribute and when found, gets data from the request.
Since I didn't like the approach of reading the request body in the ActionFilter, I changed the request and moved the data I needed from the body (server and data base names) to the url of the request. Then I created a POCO for that data that I inject into the ActionFilter and populate with the data from the url. That POCO isntance is now available in every service down the dependency chain that needs it.
For the rest of the data I needed in my SomeData object, I followed approach 1, made WorkerService's constructor parameterless and passed the data like:
_myService.DoSomething(someData);
One final trick was adding the ActionFilter to config.Filters, because my filter has it's own dependencies, I couldn't just do:
config.Filters.add(new MyActionFilter(What_About_The_Parametes_???))
I had to get the structureMap's container instance and have it return a instance of my filter which will the cause all the dependencies to be injected into it, and then I can add the filter instance to config.Filters:
var container = StructuremapMvc.StructureMapDependencyScope.Container;
config.Filters.Add(container.GetInstance<IMyActionFilter>());

How to set argument to Ninject binder regarding on request header

Problem:
I have webapi serviss where almost every user has its own database instance to connect. So i have to set different connection string for each user. To recognize user i will pass specific Token into header. Regarding on this Token, system has to build and set differenct connection string into Data Access layer constructor (Order in this case)
Question:
Is it possible to pass argument to Ninject or any kind of IoC binder regarding on request header?
IOrders _orders;
public HomeController(IOrders order)
{
_orders = order;
}
Here is an Ninject binding, but as you can guess, HttpContext.Current is null.
private static void RegisterServices(IKernel kernel)
{
var some_value = HttpContext.Current.Request.Headers.GetValues("Token");
kernel.Bind<IOrders>()
.To<Orders>()
.WhenInjectedInto<HomeController>()
.WithConstructorArgument("Token", some_value);
}
Maybe there is much elegant way to do this using Controller Factory ?
I would create a service class that does this lookup for you. then inject this service into the Orders implementation.
public interface IRequestContext {
string ConnectionString {get;}
}
public class HttpHeaderRequestContext : IRequestContext {
public string ConnectionString {
get {
var token = HttpContext.Current.Request.Headers.GetValues("Token");
// .. lookup conn string based on token
}
}
}
public class Orders : IOrders {
public Orders(IRequestContext ctx) {
// create new connection w/ ctx.ConnectionString
}
}
using this method, the lookup of headers and connection strings is abstracted away from the implementation. this makes it easier to test and easier swap out with a different method of obtaining a connection string if the need arises.
After implementing Dave approach, i realized that i could solve this connection string injection by feeding HttpContext.Current into Ninject binding like this:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IOrders>()
.To<Orders>()
.WhenInjectedInto<HomeController>()
.WithConstructorArgument("smth", x => {
var token = HttpContext.Current.Request.Headers.Get("Token");
var _db = new SomeDataCxt();
var connStr = _db.DbStringRepository.GetByToken(token);
return connStr;
});
}

Setting Session on Specific Event Calls

I have an MVC application and a custom class called AuthorisationFilter which has a .NET interface of IAuthorizationFilter, this has an OnAuthorization method which gets called when I click around my site, at that point I go about validating the security access of the user (which works), but I don't want to do this all the time as it is time consuming.
In this I'm trying to use the Session to store a temporary piece of login information (this is an internal application by the way), but I can't get it working as I'd expect. I can't just use an HttpContext so end up constantly creating a new instance of HttpContextBase, which I assume is then clearing out the Session. My code is as follows:
internal void SetSecurityLevel(int token)
{
HttpContextBase _cBase = new HttpContextWrapper(HttpContext.Current);
_cBase.Session["SecurityRights"] = token;
}
internal int GetSecurityLevel()
{
HttpContextBase _cBase = new HttpContextWrapper(HttpContext.Current);
if (_cBase.Session["SecurityRights"] == null)
{
SetSecurityLevel(-1);
}
return (int)_cBase.Session["SecurityRights"];
}
Please note this is only part of the code, SetSecurityLevel is set to the correct value by a separate method call which is not shown
Anyway what I'm really wanting to do is have the session set in this class and have it persisted. I tried a few different ways, including setting the context when the class is initialised, but I end up with a NullReference on the .Session object in GetSecurityLevel
private HttpContextBase _cBase = new HttpContextWrapper(HttpContext.Current);
public AuthorisationFilter()
{
_cBase = new HttpContextWrapper(HttpContext.Current);
}
Is there a way I can do this within the class?
You are right that you can't set in the constructor but you can in OnActionExecuting when the context is available
public override void OnActionExecuting(ActionExecutedContext filterContext)
{
_session = = filterContext.HttpContext.Session;
I would wonder a little why you're setting this security level in the filter and not just doing it directly from where it's needed.

how to unit test for session variable in controller in mvc

I am unit-testing my controller.
In one of my controller methods I am setting Session variables:
public void Index()
{ Session["foo"] = "bar";
return View();
}
How can I unit-test this? The problem is that the Session property is null when testing. Injecting is not possible because the Session property is readonly.
I don't want to use any third-party tool or mocking.
Simply dont use things like Session["foo"] in your controller methods. Best practice is keep action methods unaware of any context-like global objects. Everything your action method needs should be given to her in form of arguments. Note that built-in mechanism of model binding works exactly like that - you dont use Request.Form[], you let "somebody behind the scene" pass it to your action as argument.
Now for the session you can do the same - write you very simple ValueProvider which will know how to recognize arguments you want to fill from session, and you are done. In production your actions will work with session, in test you cant simply pass them any values you want as arguments.
For inspiration look at this http://www.prideparrot.com/blog/archive/2012/7/how_to_create_a_custom_session_value_provider
Injecting is not possible because the Session property is readonly.
This means you cannot use setter injection, but could you use constructor injection, ie add a constructor for your controller that is something like:
MyController(Session session)
{
m_session = session;
// then call your main constructor
}
Session getSession()
{
return m_session;
}
You can then use this separate constructor during testing.
I agree with #rouen. do not directly use Session["foo"]. But I think having ValueProvider ans might not be a practical solution, as we only store very few variables, and these values may be and most likely not ur full model.
So my approach is something similar to what Vic Smith suggests but a much more IOC (and Mock) friendly.
I would create a provider (i.e a service) to retrieve the session variables
public class SessionVariableProvider : ISessionVariableProvider
{
public object GetSessionValue(string key)
{
if (!HttpContext.Current.Session.IsNewSession
&& HttpContext.Current.Session[key] != null)
{
return HttpContext.Current.Session[key];
}
throw new ArgumentNullException(key);
}
public void SetSessionValue(string key, object value)
{
HttpContext.Current.Session[key] = value;
}
}
public interface ISessionVariableProvider
{
object GetSessionValue(string key);
void SetSessionValue(string key, object value);
}
Modify your Controller expect ISessionVariableProvider as a parameter.
public class TestController: Controller
{
protected readonly ISessionVariableProvider _sessionVariableProvider;
protected InowiaControllerBase(ISessionVariableProvider sessionVariableProvider)
{
Guard.ArgumentNotNull(sessionVariableProvider, "sessionVariableProvider");
this._sessionVariableProvider = sessionVariableProvider;
}
public ActionResult Index()
{
_sessionVariableProvider.SetSessionValue("foo", "bar");
var foo2 = (string)_sessionVariableProvider.GetSessionValue("foo2");
return View();
}
}
when testing create your own test implementation of ISessionVariableProvider and pass it to the controller.

How to get and set http headers in an Action, the testable way

I have an action that returns either a FileContentResult or a NotModifiedResult, which is a custom result type that returns HTTP 304 to indicate that the requested resource has not been modified, like this:
[ReplaceMissingPicture(Picture = "~/Content/Images/nothumbnail.png", MimeType = "image/png")]
public ActionResult Thumbnail(int id)
{
var item = Service.GetItem(id);
var requestTag = Request.Headers["If-None-Match"] ?? string.Empty;
var tag = Convert.ToBase64String(item.Version.ToArray());
if (tag == requestTag)
{
return new NotModifiedResult();
}
if (item.Thumbnail != null)
{
var thumbnail = item.Thumbnail.ToArray();
var mime = item.PictureMime;
Response.AppendHeader("ETag", tag);
return File(thumbnail, mime);
}
else
{
return null;
}
}
This action needs to access the Response object, which is of course not present during testing, so that makes this action untestable. I could add conditional statements around it, so that it runs during testing, but then I can't test for the headers being set correctly.
What would be a solution to this problem?
FYI, the ReplaceMissingPicture filter returns a specific resource in case null was returned from this action, to keep the MapPath() call out of the controller for the very same reason.
The first step would be to create an interface which simplifies the services you need:-
public interface IHeaders
{
public string GetRequestHeader(string headerName);
public void AppendResponseHeader(string headerName, string headerValue);
}
Now create a default implementation:-
public Headers : IHeaders
{
public string GetRequestHeader(string headerName)
{
return HttpContext.Current.Request[headerName];
}
public void AppendResponseHeader(string headerName, string headerValue)
{
HttpContext.Current.Response.AppendHeader(headerName, headerValue);
}
}
Now add a new field to your Controller:-
private IHeaders myHeadersService;
add new constructor to you controller:-
public MyController(IHeaders headersService)
{
myHeadersService = headersService;
}
modify or add the default constructor:-
public MyController()
{
myHeadersService = new Headers();
}
now in your Action code use myHeadersService instead of the Response and Request objects.
In your tests create your own implementation of the IHeaders interface to emulate/test the Action code and pass that implementation when constructing the Controller.
How about creating a subclass of FileResult--say ETagFileResult--that in its ExecuteResult() method sets the ETag header, and then defaults to the base class implementation? You can test that class with a mocked context (as you presumably are with your NotModifiedResult) to be sure that it's doing the right thing. And remove the entire complication from the testing of the controller.
Failing that, it's possible to set a mocked context on the controller in your test (after instantiating the class, before calling the action method). See this question, for instance. But that seems like more work.
(Also, by the way, it looks like you're quoting the tag value twice there: once when tag is set, and once more when you actually set the header....)

Resources