Owin running before Structure Map configuration - asp.net-mvc

On an ASP.NET MVC 5 project using OWIN I have the following:
[assembly: OwinStartup(typeof(MvcProj.Site.OwinStartup), "Configure")]
namespace MvcProj.Site {
public partial class OwinStartup {
public void Configure(IAppBuilder application) {
UrlHelper url = new UrlHelper(HttpContext.Current.Request.RequestContext);
application.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
CookieSecure = CookieSecureOption.SameAsRequest,
LoginPath = new PathString(url.Action(MVC.User.SignIn())),
ReturnUrlParameter = "redirect"
});
application.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
} // Configure
} // OwinStartup
}
As you can see I am defining the login path as follows:
LoginPath = new PathString(url.Action(MVC.User.SignIn())),
I get an error from StructureMap saying I do not have ITranslator defined ...
In fact it is defined but all my controllers are base on a BaseController:
public abstract class BaseController : Controller, ITranslator_ {
public readonly ITranslator _translator;
protected BaseController() {
_translator = ObjectFactory.Container.GetInstance<ITranslator>();
} // BaseController
public String _(String value) {
return _translator.Translate(value);
} // _
}
So what I think it happens is that Owin runs before my IoC code in global.asax Application Start.
If I remove the code line LoginPath = new PathString(url.Action(MVC.User.SignIn())) then everything works fine.
Could someone, please, tell me how to solve this?
Thank You,
Miguel

The Microsft.Owin.SystemWeb host uses the PreApplicationStartMethodAttribute to bootstrap itself which runs before your Application_Start method. This is why you're seeing the crash. You'll need to move your DI setup into the Startup class.
I've since switched from ASP.NET MVC to Nancy but your setup should be similar aside from the need to also setup a dependency resolver for MVC. For this you'll need to install StructureMap.MVC4 and then remove the StructuremapMvc class it adds since your setup code is now in the Startup class.
public class Startup
{
public void Configuration(IAppBuilder app)
{
var container = SetupStructureMap();
// sets up the mvc dependency resolver
DependencyResolver.SetResolver(new StructureMapDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new StructureMapDependencyResolver(container);
SetupAuth(app, container);
}
private static IContainer SetupStructureMap()
{
ObjectFactory.Initialize(x =>
{
// ...
});
return ObjectFactory.Container;
}
public static void SetupAuth(IAppBuilder app, IContainer container)
{
app.SetDataProtectionProvider(container.GetInstance<IDataProtectionProvider>());
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = Constants.AppAuthType,
CookieHttpOnly = true,
CookieName = "app.id",
LogoutPath = new PathString("/logout"),
Provider = container.GetInstance<ICookieAuthenticationProvider>(),
ReturnUrlParameter = string.Empty
});
}
}
My Startup class is loosely based on the one from JabbR.

Related

How to set dbContext with a connection string when it is also injected as a service

I'm using EF-Core in a web-api project, and using the DI mechanism to inject the DBContext to action methods.
BUT - In addition - I would like to reach the DB using the EF dbContext, when the server is up, in the startup method - this is a non http context, meaning - the DBContext is not initiated yet - it is initiated in the ConfigureServices method, and it is initiate after the stratup method.
For further explanation, this is the Startup.cs and the rest of the relevant flow:
public class Startup
{
public IConfiguration Configuration {get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
RepositoriesManager.Initiate(configuration);
//In addition - I now would like to use it to initiate repository by using the EF Core dbContext
//Another option is to run this methos after adding the dbContext serice - in the ConfigureServices
}
public void ConfigureServices(IServiceCollection services)
{
services.Add....
services.AddDbContext<MyDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("myDB)));
//Option to execute it here instead of in the Startup
RepositoriesManager.Initiate(configuration);
}
}
RepositoriesManager is a static class that using the configuration to get data from external API
public static Class RepositoriesManager
{
static RepositoriesManager(){} //static constructor
public static void Initiate(IConfiguration configuration)
{
//to make a long story short:
GetDataFromDBUsingEF();
}
//This method can be called also from action method (controller) - where the myDBContext is passed - this is not the case here
public static GetDataFromDBUsingEF(MyDBContext myDBContext = null)
{
if (myDBContext == null)
{
//one option - not working:
var serviceCollection = new Microsoft.Extensions.DependencyInjection.ServiceCollection();
var sp = serviceCollection.GetService<MyDBContext>();
//second option - also not working:
myDBContext = new MyDBContext(); // This should initiate the DBContext in some scenarios
}
}
}
I'm trying to use the dbContext OnConfiguration method:
protected override void OnConfiguration(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
IConfigurationRoot configuration = new ConfigurationBuilder().SetBasePath(AppDomain.CurrentDomain.BaseDirectory).AddJsonFile("appsettings.json").Build();
optionsBuilder.UseSqqlServer(configuration.GetConnectionString("<connection string key>"));
}
}
This method should be called in every DbContext initiation using its constructor.
Right now it is not being reached when I initiate the dbContext. I assume that the reason is what the documentation claims:
"If a model is explicitly set on the options for this context (via Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.UseModel(Microsoft.EntityFrameworkCore.Metadata.IModel)) then this method will not be run".
How can I get the DBContext when its not injected ?
Option 1: Get context in Startup constructor via new
public Startup(IConfiguration configuration)
{
Configuration = configuration;
var contextOptions = new DbContextOptionsBuilder<MvcContext>()
.UseSqlServer(Configuration.GetConnectionString("MvcContext"))
.Options;
using var context = new MvcContext(contextOptions);
var configFromDb = context.MvcConfiguration.First();
}
Option 2: In ConfigureServices call Configure on required options and use context (it will be called when options will be actually used)
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDbContext<MvcContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("MvcContext"));
});
services.AddOptions<DbConfigOptions>().Configure<IServiceProvider>((options, sp) =>
{
using var scope = sp.CreateScope();
using var dbContext = scope.ServiceProvider.GetRequiredService<MvcContext>();
options.UseDeveloperExceptionPage = dbContext.MvcConfiguration.Single().UseDeveloperExceptionPage;
});
}
Option 3: When DBContext is configured in ConfigureServices it can be injected in Startup.Configure and used there
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, MvcContext dbContext)
{
var configFromDb = dbContext.MvcConfiguration.Single();
//...
}

How can I get OwinContext from SignalR Hub?

I have an ASP.NET MVC 5 app that is written on the top of ASP.NET MVC 5 framework using c#.
In this app, I am using SignalR to create a WebSocket connection between my app and the user's browser.
In my SignalR hub, I want to be able to access the OwinContext object.
How can I access the OwinContext object from my hub?
This is what I tried
Context.Request.GetHttpContext().GetOwinContext();
However, this is giving me the following error
No owin.Environment item was found in the context.
I added the <add key="owin:AutomaticAppStartup" value="true" /> to my Web.Config file.
This is how Startup class look like
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Owin;
using System;
[assembly: OwinStartup(typeof(TestProject.App_Start.Startup))]
namespace TestProject.App_Start
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
ConfigureAuth(app);
// Any connection or hub wire up and configuration should go here
app.MapSignalR();
}
public void ConfigureAuth(IAppBuilder app)
{
// need to add UserManager into owin, because this is used in cookie invalidation
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = Settings.ApplicationCookie,
LoginPath = new PathString("/Login"),
Provider = new CookieAuthenticationProvider(),
CookieName = Settings.ApplicationCookieName,
CookiePath = Settings.CookiePath,
CookieHttpOnly = true,
SlidingExpiration = true,
ExpireTimeSpan = TimeSpan.FromHours(24),
});
}
}
}
UPDATED Case use explanation
In some case I need to update the user claims from inside the Hub. This requires to inform the Authentication Manager about the new claims. So I use the following method to update the ClaimsIdentity
private static void InformAuthManager(ClaimsIdentity identity, HttpContextBase context = null)
{
IAuthenticationManager authenticationManager;
if (context != null)
{
authenticationManager = context.GetOwinContext().Authentication;
}
else
{
authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
}
var claims = new ClaimsPrincipal(identity);
var authProperties = new AuthenticationProperties() { IsPersistent = true };
authenticationManager.AuthenticationResponseGrant = new AuthenticationResponseGrant(claims, authProperties);
}

MVC 5.2 Cookie Sign In OWIN and Injecting Authenticated User Information

I am in a bit of a pickle with my MVC Application due to the way I have coded up (currently) the implementations of my application services and the way they are configured for dependency injection.
I'm looking to separate the layers of the application by following SOLID principles.
The problem is that in some of these services, the constructor requires an instance of IUserContext. IUserContext contains the various information about the logged in user and will be passed around a few different layers.
public class ProjectDataLoader : DataLoaderBase, IProjectDataLoader
{
public ProjectDataLoader(IMyDbContext dbContext, IUserContext userContext)
: base (dbContext, userContext)
{
}
...
public IEnumerable<ProjectViewModel> Find(string filter = "")
{
...
}
}
And an implementation of IUserContext:
public class AspNetUserContext : IUserContext
{
...
}
I could pass IUserContext on every method call but I feel it belongs in the constructor. But that is not the question here.
When I sign in from the login page via AccountController, MyAppSignInManager.SignInOrTwoFactor gets called via the OWIN pipeline. At this point I was creating a new instance of AspNetUserContext in the session:
HttpContext.Current.Session["UserContext"] = aspNetUserContext;
Now I have custom SignInManager implementation:
public class MyAppSignInManager : SignInManager<MyAppUser, string>
{
...
}
I have a custom IUserStore implementation:
public class MyAppUserStore : IUserPasswordStore<MyAppUser>,
IUserStore<MyAppUser>
{
...
}
All of the above have been hooked up for Dependency Injection with Simple Injector my choice of container.
public static class DependencyConfig
{
public static Container Initialize(IAppBuilder app)
{
Container container = GetInitializeContainer(app);
container.Verify();
DependencyResolver.SetResolver(
new SimpleInjectorDependencyResolver(container));
return container;
}
private static Container GetInitializeContainer(IAppBuilder app)
{
var container = new Container();
RegisterCommon(container);
RegisterRepositories(container);
RegisterDataLoaders(container);
RegisterAppServices(container);
RegisterMvc(app, container);
return container;
}
private static void RegisterCommon(Container container)
{
container.Register<IUserContext>(() =>
{
IUserContext context = null;
if (HttpContext.Current.Session == null)
context = new AspNetUserContext(Guid.Empty, Guid.Empty);
else
context = (IUserContext)HttpContext.Current.Session["UserContext"];
return context;
}, Lifestyle.Transient);
}
private static void RegisterRepositories(Container container)
{
container.RegisterPerWebRequest<IUserRepository>(() =>
new UserRepository(container.GetInstance<IMyApp4Context>()));
container.Register<IMyApp4Context>(() => new MyApp4Context(),
Lifestyle.Transient);
}
private static void RegisterDataLoaders(Container container)
{
container.Register<IProjectDataLoader, ProjectDataLoader>();
container.Register<ContractDataLoader>();
container.Register<DrawingDataLoader>();
container.Register<WeldDataLoader>();
}
private static void RegisterAppServices(Container container)
{
}
private static void RegisterMvc(IAppBuilder app, Container container)
{
container.RegisterSingle(app);
container.RegisterPerWebRequest<MyAppUserManager>();
container.RegisterPerWebRequest<SignInManager<MyAppUser, string>,
MyAppAppSignInManager>();
container.RegisterPerWebRequest(() =>
{
if (HttpContext.Current != null &&
HttpContext.Current.Items["owin.Environment"] == null &&
container.IsVerifying())
{
return new OwinContext().Authentication;
}
return HttpContext.Current.GetOwinContext().Authentication;
});
container.RegisterPerWebRequest<IUserStore<MyAppUser>>(() =>
new MyAppUserStore(container.GetInstance<IUserRepository>()));
app.UseOwinContextInjector(container);
container.RegisterMvcControllers(
Assembly.GetExecutingAssembly());
}
private static void InitializeUserManager(MyAppUserManager manager, IAppBuilder app)
{
manager.UserValidator =
new UserValidator<MyAppUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
manager.PasswordValidator = new PasswordValidator()
{
RequiredLength = 6,
RequireNonLetterOrDigit = false,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
IDataProtectionProvider dataProtectionProvider =
app.GetDataProtectionProvider();
if (dataProtectionProvider != null)
{
manager.UserTokenProvider =
new DataProtectorTokenProvider<MyAppUser>(
dataProtectionProvider.Create(purposes: new string[] { "ASP.NET Identity" }));
}
}
}
And also:
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app, Container container)
{
app.CreatePerOwinContext(() => container.GetInstance<MyAppUserManager>());
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString(value: "/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<MyAppUserManager, MyAppUser>(
validateInterval: TimeSpan.FromMinutes(value: 30),
regenerateIdentity: (manager, user) =>
{
return user.GenerateUserIdentityAsync(manager);
})
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
}
}
Then these are to be used in the controllers:
public class ProjectController : MyBaseContextController
{
public ProjectController(IProjectDataLoader loader)
: base(context)
{
...
}
}
My initial question was going to be how can I get MyAppUser after the cookie authentication has taken place. Maybe asking this is still valid.
The better question is to ask what I am trying to accomplish. Essentially what I want is to inject IUserContext into my services. This needs to be injected into the constructor of the various service implementations registered in my DI container. However, this instance won't be available until a user has logged in/authenticated.
NOTE: All of the user information is stored in SQL and I use Entity Framework to access all of this.
So given that once a user has authenticated by logging in via the login page via the MyAppSignInManager.SignInOrTwoFactor method and also by a cookie, how can I make my AspNetUserContext (IUserContext) instance available to my DI container?
NOTE: I just want to get the user information from the database once - rather that every call to the controllers where it is required.
"I just want to get the user information from the database once."
You should consider storing your required user data in claims.
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString(value: "/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<MyAppUserManager, MyAppUser>(
validateInterval: TimeSpan.FromMinutes(value: 30),
regenerateIdentity: (manager, user) =>
{
return user.GenerateUserIdentityAsync(manager);
})
}
})
The GenerateUserIdentityAsync method adds the core identity claims but you can override this and store custom claims that your services need. Then instead of passing in a IUserContext to your service you could pass in an IClaimsIdentity.
This would mean you don't have to query the database all the time to get the data you need. The claims would be automatically updated after the 30 minute interval as specified in your code.
Hope this helps.

Autofac in Asp.net MVC, WebApi, SignalR, Owin yet again

How to register in a good way one Autofac dependency resolver or resolvers if one not possible for Asp.net MVC, WebApi, SignalR working together with Owin? There are guidelines for each of them. But as stated below it does not seem to work. Here is the code which is somewhat bad as it uses different dependency resolves, someones static and they seem to have one reason to exists (so looks like code duplication).
public class Startup
{
// This two static resolvers does not look nice
public static IDependencyResolver SignalRDependencyResolver { get; private set; }
public static System.Web.Http.Dependencies.IDependencyResolver WebApiDependencyResolver { get; private set; }
public void Configuration(IAppBuilder app)
{
var httpConfiguration = new HttpConfiguration();
var container = BuildAutofacContainer();
var hubConfiguration =
new HubConfiguration
{
Resolver = new AutofacDependencyResolver(container),
EnableDetailedErrors = true
};
// The resolver to be used as here. Seems to be replaced by SignalR further?
// 1. http://stackoverflow.com/questions/20139127/signalr-sending-data-using-globalhost-connectionmanager-not-working/20202040#20202040
// 2. http://stackoverflow.com/questions/20561196/signalr-calling-client-method-from-outside-hub-using-globalhost-connectionmanage
SignalRDependencyResolver = hubConfiguration.Resolver;
DependencyResolver.SetResolver(new Autofac.Integration.Mvc.AutofacDependencyResolver(container));
WebApiDependencyResolver = new AutofacWebApiDependencyResolver(container);
// Why the following does not work (throws that needs parameterless constructor) ?
// so the static resolver used
// see http://docs.autofac.org/en/latest/integration/webapi.html#owin-integration
// httpConfiguration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(httpConfiguration);
app.UseAutofacMvc();
app.UseWebApi(httpConfiguration);
app.MapSignalR("/signalr", hubConfiguration);
// AspNetIdentity hook:
app.UseCookieAuthentication(
new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login")
});
}
private static IContainer BuildAutofacContainer()
{
var builder = new ContainerBuilder();
// and http://autofac.readthedocs.org/en/latest/integration/mvc.html#using-plugin-assemblies
builder.RegisterModule<AutofacDalModule>();
builder.RegisterModule<AutofacDomainModule>();
builder.RegisterType<OperatorHubInternal>().As<IOperatorHubInternal>().SingleInstance();
RegistrationExtensions.RegisterControllers(builder, typeof(MvcApplication).Assembly);
builder.RegisterApiControllers(typeof(MvcApplication).Assembly).InstancePerRequest();
builder.RegisterHubs(Assembly.GetExecutingAssembly());
var mvcContainer = builder.Build();
return mvcContainer;
}
}

Web Api Start up Exceptions with IDependencyResolver implementation

I am developing a Web Api and I decided to use custom DependencyResolver. I refer this [Dependency Injection for Web API Controllers] article. Everything is working well so far in the terms of dependency injection into controllers. Code snippet of my configuration from my Owin startup class
private void RegisterIoC(HttpConfiguration config)
{
_unityContainer = new UnityContainer();
_unityContainer.RegisterType<IAccountService, AccountService>();
.........
.........
config.DependencyResolver = new UnityResolver(_unityContainer);
}
But at the time when Api starts for the very first time some ResolutionFailedException thrown (but catched) inside the UnityResolver's GetService method. Here is the exception message
"Exception occurred while: while resolving.
Exception is: InvalidOperationException -
The current type, System.Web.Http.Hosting.IHostBufferPolicySelector,
**is an interface and cannot be constructed. Are you missing a type mapping?**"
Above same exception thrown following types
System.Web.Http.Hosting.IHostBufferPolicySelector
System.Web.Http.Tracing.ITraceWriter
System.Web.Http.Metadata.ModelMetadataProvider
System.Web.Http.Tracing.ITraceManager
System.Web.Http.Dispatcher.IHttpControllerSelector
System.Web.Http.Dispatcher.IAssembliesResolver
System.Web.Http.Dispatcher.IHttpControllerTypeResolver
System.Web.Http.Controllers.IHttpActionSelector
System.Web.Http.Controllers.IActionValueBinder
System.Web.Http.Validation.IBodyModelValidator
System.Net.Http.Formatting.IContentNegotiator
I know that these ResolutionFailedException are thrown because I did not provide mappings in my unity configuration for above types.
Now here is my question :-, If I implement custom unity DependencyResolver I need to define mappings of above types and if need to define what will be their corresponding default implementation types OR is there some alternative way to implement DependencyResolver. I am really concerned even though application is running fine now, failing to resolve above type can cause serious issue later. Please help.
One final Addition:-
For following types, same ResolutionFailedException thrown when I make request for any action into the my web api
System.Web.Http.Dispatcher.IHttpControllerActivator
System.Web.Http.Validation.IModelValidatorCache
System.Web.Http.Controllers.IHttpActionInvoker
I was running in to the same issue using Unity with WebApi and OWIN/Katana.
The solution for me was to use the UnityDependencyResolver defined in the Unity.WebApi Nuget package instead of my own custom implementation (like #Omar Alani above)
Install-Package Unity.WebAPI
Note that the package will try and add a file named UnityConfig.cs in App_Start (the filename I used myself).
In that UnityConfig.cs file the package will add code to register the container against the GlobalConfiguration.Configuration.DependencyResolver which is not what we want with OWIN.
So instead of using:
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
Change to use:
config.DependencyResolver = new UnityDependencyResolver(container);
For completeness:
My UnityConfig.cs
public static class UnityConfig
{
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
// Your mappings here
config.DependencyResolver = new UnityDependencyResolver(container);
}
}
My Startup.cs
[assembly: OwinStartup(typeof(UnityTest.BusinessLayer.Api.ApiStartup))]
namespace UnityTest.BusinessLayer.Api
{
public partial class ApiStartup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
HttpConfiguration httpConfig = new HttpConfiguration();
UnityConfig.Register(httpConfig);
ConfigureAuth(app); //In App_Start ->Startup.Auth
WebApiConfig.Register(httpConfig);
app.UseWebApi(httpConfig);
}
}
}
In case any of the above solutions still don't work for people, here's how I solved it.
After spending a day chasing down this error, it turned out to be some sort of VS caching issue. Out of desperation, I deleted all .suo files and force-get-latest, which seems to have resolved the issue.
This has been asked a long time ago, but I encountered a solution that wasn't mentioned here so maybe someone is still interested.
In my case, these exceptions were already caught internally by Unity (or whatever), but my Exception Settings in Visual Studio made them still show up. I just had to uncheck the "Break when this exception type is shown" check box and the application went on functioning normally.
The implementation of Unity.WebAPI is not very different from the one mentioned in the question. I liked the version referred to by the OP as it ignores only ResultionFailedException and lets the rest propagate up the stack. Unity.WebAPI suppresses all exceptions. What I'd do is ignore errors that we know are safe to do so and log (or rethrow) others.
public object GetService(Type serviceType)
{
try
{
return container.Resolve(serviceType);
}
catch(ResolutionFailedException ex)
{
if (!(typeof(System.Web.Http.Tracing.ITraceWriter).IsAssignableFrom(serviceType))
|| typeof(System.Web.Http.Metadata.ModelMetadataProvider).IsAssignableFrom(serviceType)
//...
))
{
// log error
}
}
return null;
}
Normally, you don't need to with Unity.
I use this implementation for IDependencyResolver with unity, and I don't have to register or map other than my interfaces/services.
public class UnityDependencyInjectionResolver : Disposable, IDependencyResolver
{
protected IUnityContainer Container;
public UnityDependencyInjectionResolver(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
Container = container;
}
public object GetService(Type serviceType)
{
try
{
return Container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
public T GetService<T>()
{
try
{
var serviceType = typeof(T);
return (T)Container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return default(T);
}
}
public T GetService<T>(string name)
{
try
{
var serviceType = typeof (T);
return (T) Container.Resolve(serviceType, name);
}
catch (ResolutionFailedException)
{
return default(T);
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return Container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
public IDependencyScope BeginScope()
{
var child = Container.CreateChildContainer();
return new UnityDependencyInjectionResolver(child);
}
protected override void DisposeManagedResources()
{
if (Container == null)
{
return;
}
Container.Dispose();
Container = null;
}
}
where Disposable is just a base class implements IDispoable.
Hope that helps.
As this seems to still get disputed, here's my version of the code...
/// <summary>
/// Specifies the Unity configuration for the main container.
/// </summary>
public class UnityConfig
{
private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
/// <summary>
/// Gets the configured Unity container.
/// </summary>
public static IUnityContainer GetConfiguredContainer()
{
return container.Value;
}
public static void RegisterTypes(IUnityContainer container)
{
// Keeping this separate allows easier unit testing
// Your type mappings here
}
}
and
[assembly: OwinStartup(typeof(UnityTest.BusinessLayer.Api.ApiStartup))]
namespace UnityTest.BusinessLayer.Api
{
public static HttpConfiguration Config { get; private set; }
public partial class ApiStartup
{
public void Configuration(IAppBuilder app)
{
// IoC
var container = UnityConfig.GetConfiguredContainer();
var resolver = new UnityHierarchicalDependencyResolver(container); // Gets us scoped resolution
app.UseDependencyResolverScope(resolver); // And for the OWIN
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
// NB Must be before WebApiConfig.Register
ConfigureAuth(app); //In App_Start ->Startup.Auth
// See http://stackoverflow.com/questions/33402654/web-api-with-owin-throws-objectdisposedexception-for-httpmessageinvoker
// and http://aspnetwebstack.codeplex.com/workitem/2091
#if SELFHOST
// WebAPI configuration
Config = new HttpConfiguration
{
DependencyResolver = resolver
};
WebApiConfig.Register(Config);
app.UseWebApi(Config);
#else
GlobalConfiguration.Configuration.DependencyResolver = resolver;
// http://stackoverflow.com/questions/19907226/asp-net-webapi-2-attribute-routing-not-working
// Needs to be before RouteConfig.RegisterRoutes(RouteTable.Routes);
GlobalConfiguration.Configure(WebApiConfig.Register);
Config = GlobalConfiguration.Configuration;
#endif
// Now do MVC configuration if appropriate
}
}
}
Finally bits are the extensions to use the scoped container in the Owin middleware as well as straight WebAPI
public static class AppBuilderExtensions
{
public static IAppBuilder UseDependencyResolverScope(this IAppBuilder app, IDependencyResolver resolver)
{
return app.Use<DependencyResolverScopeMiddleware>(resolver);
}
}
/// <summary>
/// Wraps middleware in a <see cref="IDependencyResolver"/> scope.
/// </summary>
public class DependencyResolverScopeMiddleware : OwinMiddleware
{
private readonly IDependencyResolver resolver;
public DependencyResolverScopeMiddleware(OwinMiddleware next, IDependencyResolver resolver) : base(next)
{
this.resolver = resolver;
}
public override async Task Invoke(IOwinContext context)
{
using (var scope = resolver.BeginScope())
{
context.SetDependencyScope(scope);
await Next.Invoke(context);
}
}
}
The rationale for this is the original MVC Work Item where we see
kichalla wrote Oct 27, 2014 at 4:34 PM
Yes...right...UseWebApi extension should be used only with
self-hosting scenarios...since we are all on the same page, I am
closing this issue as by-design...please let us know if you have any
more questions...
Thanks, Kiran
and
kichalla wrote Oct 29, 2014 at 5:28 PM
#thebothead: Thanks for finding this out!...right, this sample
shouldn't have been using Microsoft.AspNet.WebApi.Owin in IIS as it
was never intended to be used in that host...we will investigate the
issue further to see why this exception happens...but meanwhile you
could follow the approach mentioned in the sample that I provided
earlier...
Thanks, Kiran
From my own experience if you don't use this form of the code, it will work in debug etc but will not scale and start behaving strangely.
I has deleted dependencyResolver and this problem was solved
public static class UnityConfig
{
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
// Your mappings here
config.DependencyResolver = null;
}
}

Resources