Currently I have an ActionFilter that gets the current users name from HttpContext and passes it into the action which uses it on a service method. eg:
Service.DoSomething(userName);
I now have a reason to do this not at the action level but the controller constructor level. Currently I'm using structure map to create controllers and inject the service. I'm looking at something like:
public interface IUserProvider
{
string UserName { get; }
}
public class HttpContextUserProvider : IUserProvider
{
private HttpContext context;
public HttpContextUserProvider(HttpContext context)
{
this.context = context;
}
public string UserName
{
get
{
return context.User.Identity.Name;
}
}
}
That said, my IoC foo is really weak as this is the first project I've used it on.
So my question is... how can I tell structure map to pass in HttpContext in the constructor for HttpContextUserProvider? This just seems weird... I'm not sure how to think of HttpContext.
It sounds like you should be using HttpContextBase instead of HttpContextUserProvider. This is a out-of-box abstraction of HttpContext and allows you to create a mock, write UnitTests and inject your dependencies.
public class SomethingWithDependenciesOnContext
{
public SomethingWithDependenciesOnContext(HttpContextBase context) {
...
}
public string UserName
{
get {return context.User.Identity.Name;}
}
}
ObjectFactory.Initialize(x =>
x.For<HttpContextBase>()
.HybridHttpOrThreadLocalScoped()
.Use(() => new HttpContextWrapper(HttpContext.Current));
Have an interface abstract HttpContext.Current. Expose only the methods you need. GetUserName() would call HttpContext.Current.User.Identity.Name in the implementation, for example. Make that as thin as possible.
Take that abstraction and inject it into your other provider class. This will allow you to test the provider by mocking the http context abstraction. As a side benefit, you can do other nifty things with that HttpContext abstraction besides mock it. Reuse it, for one thing. Add generic type params to bags, etc.
I'm not sure why you're bothering. It seems like just using HttpContext.Current directly in HttpContextUserProvider is the right thing to do. You're never going to be substituting in a different HttpContext...
Maybe I left something out, but the above answer doesn't work for me (has since been deleted -- it was still a useful answer though -- it showed how to tell SM to pass constructor arguments). Instead if I do:
ObjectFactory.Initialize(x =>
{
x.BuildInstancesOf<HttpContext>()
.TheDefault.Is.ConstructedBy(() => HttpContext.Current);
x.ForRequestedType<IUserProvider>()
.TheDefault.Is.OfConcreteType<HttpContextUserProvider>();
});
I get it to work. I did this after finding: If you need something in StructureMap, but you can’t build it with new()…
Edit:
Thanks to Brad's answer I think I have a better handle on HttpContext. His answer definitely works, I just am not sure I like having the call to HttpContext.Current inside a class (it seems like it hides the dependency, but I'm far from an expert on this stuff).
The above code should work for injecting HttpContext as far as I can tell. Matt Hinze brings up the added that point that if all I need from HttpContext is the User.Identity.Name, my design should be explicit about that (having an Interface around HttpContext only exposing what I need). I think this is a good idea.
The thing is over lunch I kinda realized my service really only needs to depend on a string: userName. Having it depend on IUserProvider might not have much added value. So I know I don't want it to depend on HttpContext, and I do know all I need is a string (userName) -- I need to see if I can learn enough StructureMap foo to have make this connection for me. (sirrocoo's answer gives a hint on where to start but he deleted it :*( ).
Related
I have tried most of the examples in the Google Results, Stackoverflow and in AutoMapper. But was not able to get the IValueResolverdependancy injection to work.
I have below service
public class StorageService : IStorageService
{
private readonly BlobServiceSettings _blobServiceSettings;
public StorageService(IOptions<BlobServiceSettings> blobServiceSettings)
{
_blobServiceSettings = blobServiceSettings.Value;
}
// some methods I need
}
This is my profile
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<Building, BuildingEnvelope>(MemberList.None)
.ForMember(dest => dest.ImageUrl, opt => opt.ResolveUsing<BuildingImageUrlResolver>());
}
}
this is my IValueResolver
public class BuildingImageUrlResolver : IValueResolver<Building, BuildingEnvelope, string>
{
private readonly IStorageService _storageService;
public BuildingImageUrlResolver(IStorageService storageService)
{
_storageService = storageService;
}
public string Resolve(Building entity, BuildingEnvelope envelope, string member, ResolutionContext context)
{
return _storageService.MyMethod(entity.ImageFileName);
}
}
I get the below error in my inner exception
No parameterless constructor defined for this object.
Not sure what I am doing wrong.
Thanks in advance
Neo
Lucian's suggestion is correct -- the AutoMapper.Extensions.Microsoft.DependencyInjection package is the way to go. Even if you don't want to use it, you'll have to do something similar.
I've had this very same problem and by using the extensions, you just modify the entrypoint from which you register AutoMapper and its configuration.
What the extensions do (source) is:
Initializes Automapper with the configuration provided
It scans for all classes you have that you could be implementing with dependency injection and registers them as transient, looking for implementations of the following:
IValueResolver
IMemberValueResolver
ITypeConverter
IMappingAction
The assemblies that it will scan actually depend on the parameters that you provide on the call.
If any of these can be actually instantiated, then they will be registered as transient implementation.
And just like that, AutoMapper will request instances of these to the service provider, which will resolve them, and to do that, it will also resolve any pending dependencies.
Note that this is actually very simple -- the most difficult part is scanning the right assemblies and registering the right classes. You can do it manually too, but these extensions already take care of it for you.
Mind you, even when reflection has been improved a lot, this process is relatively slow, so try not to abuse it too much (for instance, in tests).
Finally, if none of that works for you, remember that you need to setup AutoMapper to use the dependency injection resolver too:
automapperConfiguration.ConstructServicesUsing(serviceProvider.GetService);
I'm not very experienced with Ninject, so I may have a concept completely wrong here, but this is what I want to do. I have a multi-tenant web application and would like to inject a different class object depending on what URL was used to come to my site.
Something along the lines of this, although maybe I can use .When() in the binding, but you get the idea:
private static void RegisterServices(IKernel kernel)
{
var currentTenant = TenantLookup.LookupByDomain(HttpContext.Current.Request.Url.Host.ToLower());
if (currentTenant.Foldername == "insideeu")
{ kernel.Bind<ICustomerRepository>().To<AXCustomerRepository>(); }
else
{ kernel.Bind<ICustomerRepository>().To<CustomerRepository>(); }
...
The problem is that HttpContext.Current is null at this point. So my question is how can I get the HttpContext data in NinjectWebCommon.RegisterServices. Any direction on where I might be going wrong with Ninject would be much appreciated as well.
Thank you
The problem is that your binding here resolves at compile time; whereas you need it to resolve at runtime, for every request. To do this, use ToMethod:
Bind<ICustomerRepository>().ToMethod(context =>
TenantLookup.LookupByDomain(HttpContext.Current.Request.Url.Host.ToLower()).Foldername == "insideeu"
? new AXCustomerRepository() : new CustomerRepository());
This means that, every time the ICustomerRepository is called for, NInject will run the method using the current HttpContext, and instantiate the appropriate implementation.
Note that you can also use Get to resolve to the type rather than to the specific constructor:
Bind<ICustomerRepository>().ToMethod(context =>
TenantLookup.LookupByDomain(HttpContext.Current.Request.Url.Host.ToLower())
.Foldername == "insideeu" ?
context.Kernel.Get<AXCustomerRepository>() : context.Kernel.Get<CustomerRepository>()
as ICustomerRepository);
Recently I was reading a lot of stuff about application design patterns: about DI, SL anti-pattern, AOP and much more. The reason for this - I want to come to a design compromise: loosely coupled, clean and easy to work with. DI seems ALMOST like a solution except one problem: cross-cutting and optional dependencies leading to constructor or property pollution. So I come with my own solution for this and I want to know what do you think of it.
Mark Seemann (the author of DI book and famous "SL is anti-patter" statement) in his book mentions a pattern called Ambient Context. Though he says he doesn't like it much, this pattern is still interesting: it's like old good singleton except it is scoped and provide default value so we don't have to check for null. It has one flaw - it doesn't and it can't know about it's scope and how to dispose itself.
So, why not to apply Service Locator here? It can solve problem of both scoping and disposing of an Ambient Context objects. Before you say it's anti-pattern: it is when you hide a contract. But in our case we hide OPTIONAL contract, so it's not so bad IMO.
Here some code to show what I mean:
public interface ILogger
{
void Log(String text);
}
public interface ISomeRepository
{
// skipped
}
public class NullLogger : ILogger
{
#region ILogger Members
public void Log(string text)
{
// do nothing
}
#endregion
}
public class LoggerContext
{
public static ILogger Current
{
get
{
if(ServiceLocator.Current == null)
{
return new NullLogger();
}
var instance = ServiceLocator.Current.GetInstance<ILogger>();
if (instance == null)
{
instance = new NullLogger();
}
return instance;
}
}
}
public class SomeService(ISomeRepository repository)
{
public void DoSomething()
{
LoggerContext.Current.Log("Log something");
}
}
Edit: I realize that asking not concrete question goes in conflict with stack overflow design. So I will mark as an answer a post best describing why this design is bad OR better giving a better solution (or maybe addition?). But do not suggest AOP, it's good, but it's not a solution when you really want to do something inside your code.
Edit 2: I added a check for ServiceLocator.Current is null. It's what I intent my code to do: to work with default settings when SL is not configured.
You can add cross-cutting concerns using hand-crafted decorators or some kind of interception (e.g. Castle DynamicProxy or Unity's interception extension).
So you don't have to inject ILogger into your core business classes at all.
A problem with an ambient context as the one you propose, is that it makes testing much harder. For a couple of reasons:
While running your unit tests, there must always be a valid instance registered in "ServiceLocator.Current". But not only that, it must be registered with a valid ILogger.
When you need to use a fake logger in a test (other than the simple
NullLogger), you will have to configure your container, since there
is no way in hooking into this, but since the container is a singleton, all other tests will use that same logger.
It will be non-trivial (and a waste of time) to create a solution that works when your unit tests are run in parallel (as MSTest does by default).
All these problems can be solved by simply injecting ILogger instances into services that need it, instead of using a Ambient Context.
And if many classes in your system depend on that ILogger abstraction, you should seriously ask your self whether you're logging too much.
Also note that dependencies should hardly ever be optional.
I am following Steven Sanderson's Pro MVC2 book and have a question about using Ninject.
In the sports store example, we have in Global.asax.cs
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
and NinjectControllerFactory is defined as:
public class NinjectControllerFactory : DefaultControllerFactory
{
//A Ninject "kernet" is the thing that can supply object instances
private IKernel kernel = new StandardKernel(new SportsStoreServices());
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
return (IController)kernel.Get(controllerType);
}
private class SportsStoreServices : NinjectModule
{
public string QString = null;
public override void Load()
{
Bind<IProductsRepository>().To<SqlProductsRepository>()
.WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["AppDb"].ConnectionString);
}
}
}
As you see the SqlProductsRepository is taking the connection string from the configuration file. If I need to make a decision here based on the URL query string parameters e.g. if param1=true I want to load from one repository versus the other, how can I do that? I have tried to see how to access query parameters in Load() method but I am not able to find a prepopulated place for that.
Also is Load() the right place to make a decision based on query parameters or should I somehow make this decision in Controller?
One would have multiple bindings that have .WithMetadata (or the special case thereof, are .Named()). Then, when resolving, you need to pass in a metadata filter and/or name parameter into the .Get<>() call to indicate the bindings. A small but of searching around here will yield examples, but by far the best source of ninject examples is the ninject tests, which are really clean and one of the reasons the ninject docs dont get the love they deserve (i.e. a v2 update).
i.e., you put a name or metadata filter in as an extra param into the:
return (IController)kernel.Get(controllerType, **here**);
As for best practice on how to manage this in more complex situations, I personally would go read Brand Wilson's set of posts on how they did it in MVC 3.
I guess it depends on your destination and aims:
making a sample do something while you learn - lash in the above
sort out DI based architecture to make you happy, run and buy Dependency Injection in .NET by Mark Seemann, strongly consider ASP.NET MVC 3 and read the Brad Wilson article series either way
a Module's Load() method only gets called when the application starts and the kernel is intialized. hence, there is no request context to make decisions on.
if it were me, I would inject both repositories into the controller and have the controller make the decisions on which to use. that way you can write unit tests to verify it's making the correct decisions.
Both have Request and Response properties, but I can't write a method that takes either HttpContext or HttpContextBase. In some places either one or the other is available so I need to handle both. I know HttpContextWrapper can convert in one direction, but still... why is it like this?
HttpContext has been around since .NET 1.0. Because of backward compatibility reasons, they can't change that class. HttpContextBase was introduced in ASP.NET MVC to allow for better testability because it makes it easier to mock/stub it.
This is an old question but I just had the same problem and the answer is in Gunder's comment.
Create you methods to use HttpContectBase and then wrap your context in a HttpContextWrapper when you want to call it from your code
public class SomeClass{
... other stuff in your class
public void MyMethod(HttpContextBase contextbase){
...all your other code
}
}
Usage
var objSomeClass = new SomeClass();
objSomeClass.MyMethod(new HttpContextWrapper(HttpContext.Current));
I think HttpContext.Current will be null if you make this call via ajax, I will investigate how to get the context and update this post.