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;
}
}
Related
I'm working in an Azure webJob.
I'm using autofac with a IJobActivator an everything is ok.
But now, I need to call code that is using IServiceProvider and at that moment I get an error from Autofac because IServiceProvider is not known.
When I'm using the Microsoft.Extensions.DependencyInjection.ServiceCollection() to register my Interfaces in place of Autofac it is working (I don't know where the IServiceProvider is registered but it is working).
The company I work for is asking me to explicitly use Autofac.
I struggle to find to way to use Autofac but declare the IServiceProvider within the WebJob.
Have someone an idea?
I need to call code that is using IServiceProvider and at that moment I get an error from Autofac because IServiceProvider is not known.
Does that mean when running your Webjob, you could not find the IServiceProvider in AutofacActivator.
I am not clear about how do you define IServiceProvider and how do you inject it?
I think you could inject IServiceProvider into job activator and register it then you could use this instance to get service.
You could register the IServiceProvider interface before build in ContainerConfig:
public static class ContainerConfig
{
public static IContainer GetContainer()
{
var builder = new ContainerBuilder();
builder.RegisterType<Functions>();
builder.RegisterType<HelloGenerator>().As<IStringGenerator>().SingleInstance();
builder.Register<IServiceProvider>(context =>
{
var serviceCollection = new ServiceCollection();
//todo: register the interfaces
return serviceCollection.BuildServiceProvider();
}).SingleInstance();
return builder.Build();
}
}
Get service when triggered in Functions:
public class Functions
{
private readonly IStringGenerator _stringGenerator;
private readonly IServiceProvider _serviceProvider;
public Functions(IStringGenerator strGenerator,IServiceProvider serviceProvider)
{
_stringGenerator = strGenerator;
_serviceProvider = serviceProvider;
}
public void ProcessQueueMessage([QueueTrigger("queue")] string message, TextWriter log)
{
log.WriteLine(_stringGenerator.GetWord());
log.WriteLine(_serviceProvider.GetService(xxxxxx));
}
}
In Progtam:
static void Main()
{
var config = new JobHostConfiguration
{
JobActivator = new AutofacActivator(ContainerConfig.GetContainer())
};
var host = new JobHost(config);
host.RunAndBlock();
}
In AutofacActivator:
public class AutofacActivator : IJobActivator
{
private readonly IContainer _container;
public AutofacActivator(IContainer container)
{
_container = container;
}
public T CreateInstance<T>()
{
return _container.Resolve<T>();
}
}
If this is not what you want, hope you could give me more detailed description and your main idea code.
In fact I solved my issue by using Extensions:
using Autofac.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
by using them doing the following:
_containerBuilder = new ContainerBuilder();
_containerBuilder.Populate(new ServiceCollection());
_containerBuilder.RegisterType<MyGreatType>().InstancePerDependency();
_container = _containerBuilder.Build();
It generates automatically the IServiceProvider for you
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);
}
When I create MVC 5 application in Visual Studio 2013, and choose Individual accounts as authentication then scaffolding automatically configures ASP Net Identity. It creates several classes along with ApplicationDbContext and ApplicationUserManager. It also registers these classes with OWIN context as below to use single instance per request.
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
}
basically it registers static Create method of each class. This static method is responsible for creating instance of that class.
Quesion
1>If I don't want to use static create method, is the approach below correct?.
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>
{
public ApplicationDbContext(string connString)
: base(connString)
{
}
}
public void ConfigureAuth(IAppBuilder app)
{
var conString = ConfigurationManager.ConnectionStrings["Myconnection"].ConnectionString
app.CreatePerOwinContext(()=>new ApplicationDbContext(conString));
}
2> How do I register ApplicationUserManager without using the static Create method. (It must set UserValidator,PasswordValidator, UserTokenProvider etc)
Should I set Validators and UserTokenProvider in ApplicationUserManager's constructor? Like below
public class ApplicationUserManager : UserManager<ApplicationUser, string>
{
public ApplicationUserManager(ApplicationUserStore store)
: base(store)
{
base.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
// Configure validation logic for passwords
base.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
base.EmailService = new EmailService();
//?????????How do I get options.DataProtectionProvider ??????
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
base.UserTokenProvider =
new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
}
3>In approach above How do I register ApplicationUserManager with OWIN context so that it create single instance per request? 'ApplicationUserManager also requires ApplicationUserStore and ApplicationDbContext..how do I pass those to ApplicationUserManager's constructor?
I am using asp.net identity in my project and using structuremap as DI framework. the problem is when i use constructor injection then ApplicationUserManager not configured all of it's members e.g TokenProvider, ...
this is my ApplicationUserManager class:
public class ApplicationUserManager : UserManager<User, long>
{
public ApplicationUserManager(IUserStore<User, long> store)
: base(store)
{
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new CustomUserStore(context.Get<InsuranceManagementContext>()));
// Configure the application user manager
manager.UserValidator = new UserValidator<User, long>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = false
};
manager.PasswordValidator = new PasswordValidator
{
RequireDigit = true,
RequiredLength = 8,
RequireLowercase = false,
RequireNonLetterOrDigit = true,
RequireUppercase = false
};
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider =
new DataProtectorTokenProvider<User, long>(dataProtectionProvider.Create("TEST"));
}
return manager;
}
}
this is Startup.Auth class:
public partial class Startup
{
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
app.CreatePerOwinContext(InsuranceManagementContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// Enable the application to use a cookie to store information for the signed in user
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
ExpireTimeSpan = TimeSpan.FromHours(2.0),
AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
});
}
}
and its my AccountController:
public class AccountController : BaseController
{
private ApplicationUserManager _userManager;
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
public AccountController(ApplicationUserManager userManager)
{
UserManager = userManager;
}
}
my question is how can i configure my ApplicationUserManager with structuremap?
if i set it as the below code it works but i don't know it is a good solution or not:
ObjectFactory.Initialize(x =>
{
...
x.For<ApplicationUserManager>().Use(() => HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>());
...
});
please hint me if there is a better solution and if it is ok then what is the best lifetime for it? HttpContextScope, Singleton, ...?
Before you create the StructureMap configuration for this, it helps to know how you would create it manually, i.e., if you actually "new up" everything yourself.
UserManager has a dependency on IUserStore, and its EntityFramework implementation (UserStore) has a dependency on DbContext.
Doing everything manually would look like this:
var dbContext = new IdentityDbContext("Your ConnectionString Name");
var userStore = new UserStore<IdentityUser>(dbContext);
var userManager = new UserManager<IdentityUser>(userStore);
(Replace IdentityUser with your custom user, if you are using one)
You can then configure UserManager like this:
userManager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6
};
The most complicated part about configuring userManager is related to the UserTokenProvider (that uses the data protection api), if you would do it manually it would look like this:
var dataProtectionProvider = new DpapiDataProtectionProvider("Application name");
var dataProtector = dataProtectionProvider.Create("Purpose");
userManager.UserTokenProvider = new DataProtectorTokenProvider<IdentityUser>(dataProtector);
Here's an example of a StructureMap registry (you can extrapolate from this example and adapt it to your own needs):
public DefaultRegistry() {
Scan(
scan => {
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.With(new ControllerConvention());
});
For<IUserStore<IdentityUser>>()
.Use<UserStore<IdentityUser>>()
.Ctor<DbContext>()
.Is<IdentityDbContext>(cfg => cfg.SelectConstructor(() => new IdentityDbContext("connection string")).Ctor<string>().Is("IdentitySetupWithStructureMap"));
ForConcreteType<UserManager<IdentityUser>>()
.Configure
.SetProperty(userManager => userManager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6
})
.SetProperty(userManager => userManager.UserValidator = new UserValidator<IdentityUser>(userManager));
}
I wrote a blog post about this, it explains the process that lead to this configuration, there's also a link to an example on github of an MVC project where, using this configuration, you can create, list and delete users.
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.