I'm currently working on a Xamarin.Forms application using Prism and Unity as my IoC container.
I'm also attempting to add the business logic framework CSLA to my application.
There is a Xamarin sample provided here:
https://github.com/MarimerLLC/csla/blob/main/Samples/XamarinExample/XamarinExample/XamarinExample/App.xaml.cs
In particular, everything seems to be wired up using this piece of code:
public App()
{
InitializeComponent();
var services = new ServiceCollection();
services.AddCsla();
services.AddTransient(typeof(DataAccess.IPersonDal), typeof(DataAccess.PersonDal));
serviceProvider = services.BuildServiceProvider();
ApplicationContext = serviceProvider.GetRequiredService<ApplicationContext>();
MainPage = new AppShell();
}
I'm trying to figure out how to fit that sort of code / registration into the Prism framework with Unity as the IoC container. Is this a time when I'd need to use the extensions? I saw those, but I was still coming up a little short on understanding what I should be doing.
I feel like there's a fundamental misunderstanding on my part of what I should be trying to achieve here, so any guidance on what direction I should be going in would be great.
You have to dig into AddCsla() and replicate all the registrations that are done in there.
The rest is easy:
services.AddTransient(typeof(DataAccess.IPersonDal), typeof(DataAccess.PersonDal));
ApplicationContext = serviceProvider.GetRequiredService<ApplicationContext>();
is trivial to translate to Unity
unityContainer.RegisterType<DataAccess.IPersonDal, DataAccess.PersonDal>();
ApplicationContext = unityContainer.Resolve<ApplicationContext>();
or Prism's "abstraction layer"
containerRegistry.Register<DataAccess.IPersonDal, DataAccess.PersonDal>();
ApplicationContext = containerRegistry.Resolve<ApplicationContext>();
I think this may be what I'm looking for:
protected override IContainerExtension CreateContainerExtension() {
var containerExtension = base.CreateContainerExtension();
var services = new ServiceCollection();
services.AddCsla();
var serviceProvider = ((UnityContainerExtension)containerExtension).Instance.BuildServiceProvider(services);
ApplicationContext = serviceProvider.GetRequiredService<ApplicationContext>();
return containerExtension;
}
Basically, it seems that I can override the container creation in my app.cs. From there I can call whatever methods I'd like against the ServiceCollection, build the container using the extension (in this case Unity) and return that container to the application.
Testing this in code I can see that I'm now able to inject the IDataPortalFactory into my view model along with the IServiceProvider, and the IServiceProvider is of type Unity.Microsoft.DependencyInjection.ServiceProvider.
public MainPageViewModel(
INavigationService navigationService,
IServiceProvider serviceProvider,
IDataPortalFactory dataPortalFactory,
ITestClassFactory testClassFactory)
: base(navigationService) {
Title = "Main Page";
this.serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
this.dataPortalFactory = dataPortalFactory ?? throw new ArgumentNullException(nameof(dataPortalFactory));
this.testClassFactory = testClassFactory ?? throw new ArgumentNullException(nameof(testClassFactory));
}
So, if I'm getting IDataPortalFactory in my view model, I'm assuming my call to AddCsla() worked, and if the IServiceProvider is considered to be a Unity service provider, I must have successfully replaced the Service Provider implementation.
Related
We are transitioning from Xamarin.Forms to .Net MAUI but our project uses Prism.Unity.Forms. We have a lot of code that basically uses the IContainer.Resolve() passing in a collection of ParameterOverrides with some primitives but some are interfaces/objects. The T we are resolving is usually a registered View which may or may not be the correct way of doing this but it's what I'm working with and we are doing it in backend code (sometimes a service). What is the correct way of doing this Unity thing in DryIoC? Note these parameters are being set at runtime and may only be part of the parameters a constructor takes in (some may be from already registered dependencies).
Example of the scenario:
//Called from service into custom resolver method
var parameterOverrides = new[]
{
new ParameterOverride("productID", 8675309),
new ParameterOverride("objectWithData", IObjectWithData)
};
//Custom resolver method example
var resolverOverrides = new List<ResolverOverride>();
foreach(var parameterOverride in parameterOverrides)
{
resolverOverrides.Add(parameterOverride);
}
return _container.Resolve<T>(resolverOverrides.ToArray());
You've found out why you don't use the container outside of the resolution root. I recommend not trying to replicate this error with another container but rather fixing it - use handcoded factories:
internal class SomeFactory : IProductViewFactory
{
public SomeFactory( IService dependency )
{
_dependency = dependency ?? throw new ArgumentNullException( nameof(dependency) );
}
#region IProductViewFactory
public IProductView Create( int productID, IObjectWithData objectWithData ) => new SomeProduct( productID, objectWithData, _dependency );
#endregion
#region private
private readonly IService _dependency;
#endregion
}
See this, too:
For dependencies that are independent of the instance you're creating, inject them into the factory and store them until needed.
For dependencies that are independent of the context of creation but need to be recreated for each created instance, inject factories into the factory and store them.
For dependencies that are dependent on the context of creation, pass them into the Create method of the factory.
Also, be aware of potential subtle differences in container behaviours: Unity's ResolverOverride works for the whole call to resolve, i.e. they override parameters of dependencies, too, whatever happens to match by name. This could very well be handled very differently by DryIOC.
First, I would agree with the #haukinger answer to rethink how do you pass the runtime information into the services. The most transparent and simple way in my opinion is by passing it via parameters into the consuming methods.
Second, here is a complete example in DryIoc to solve it head-on + the live code to play with.
using System;
using DryIoc;
public class Program
{
record ParameterOverride(string Name, object Value);
record Product(int productID);
public static void Main()
{
// get container somehow,
// if you don't have an access to it directly then you may resolve it from your service provider
IContainer c = new Container();
c.Register<Product>();
var parameterOverrides = new[]
{
new ParameterOverride("productID", 8675309),
new ParameterOverride("objectWithData", "blah"),
};
var parameterRules = Parameters.Of;
foreach (var po in parameterOverrides)
{
parameterRules = parameterRules.Details((_, x) => x.Name.Equals(po.Name) ? ServiceDetails.Of(po.Value) : null);
}
c = c.With(rules => rules.With(parameters: parameterRules));
var s = c.Resolve<Product>();
Console.WriteLine(s.productID);
}
}
I have been looking into the new features of the new version of ASP.NET Identity 2.1 and one of its enhancements is the new IoC features integrated into the OWIN Middleware.
One of the sentences that I looked in the examples is this one:
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
This sentence receives a function delegate which returns a new instance of a manager implementation provided on the examples:
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options,
IOwinContext context)
{
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
I personally dont like this implementation because I am not able to use a container to inject any dependency that I want for these managers.
Also there is an "IdentityFactoryOptions" and a "IOwinContext" that are "magically" injected to the function which Im not able to pull out into my IoC container.
Do anyone have a better workaround on this implementation?
I'm starting from an out-of-the-box MVC5 installation and using AutoFac as an IoC container. It sounds like I am trying to acheive a similar goal as you, so let me explain what I've done. As a disclaimer, I am fairly new to using IoC and to Identity.
I believe the IOwinContext is unnecessary in a role as an IoC if you are using your own - I switched over to registering my ApplicationUserManager with AutoFac. To achieve this I had to:
Remove CreatePerOwinContext lines from Startup.Auth since I'll register ApplicationDbContext and ApplicationUserManager in AutoFac.
//app.CreatePerOwinContext(ApplicationDbContext.Create);
//app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
Modify the ApplicationUserManager constructor arguments and included everything from the Create function.
public ApplicationUserManager(IUserStore<ApplicationUser> store, IdentityFactoryOptions<ApplicationUserManager> options)
: base(store)
{
//all the code from the 'Create' function here, using `this` for `manager`
}
Set the AccountController to have a single constructor taking an ApplicationUserManager as an argument and scrapped the UserManager property that grabs the ApplicationUserManager from the OwinContext.
private ApplicationUserManager _userManager; //every thing that needs the old UserManager property references this now
public AccountController(ApplicationUserManager userManager)
{
_userManager = userManager;
}
Register everything with AutoFac, including an instance of IdentityFactoryOptions.
var x = new ApplicationDbContext();
builder.Register<ApplicationDbContext>(c => x);
builder.Register<UserStore<ApplicationUser>>(c => new UserStore<ApplicationUser>(x)).AsImplementedInterfaces();
builder.Register<IdentityFactoryOptions<ApplicationUserManager>>(c => new IdentityFactoryOptions<ApplicationUserManager>()
{
DataProtectionProvider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider("ApplicationName")
});
builder.RegisterType<ApplicationUserManager>();
That's the rough summary. I may have missed a couple of other tweaks I had to do along the way.
Ben's answer gets the general idea right, but it manually instantiates the DbContext and uses this instance when registering the rest of the types. IMO, that's a bad idea (one shouldn't use the same eternal db context for ALL requests).
Derek's comment is a big improvement, but it doesn't pass the database context to the user store, resulting in errors such as "The entity type ApplicationUser is not part of the model for the current context.".
I've included my code below, for reference - it's really similar to Derek's.
builder.RegisterType<MyApplicationContext>().AsSelf().InstancePerRequest()
//...
builder.RegisterType<ApplicationUserManager>().AsSelf().InstancePerRequest();
builder.RegisterType<ApplicationSignInManager>().AsSelf().InstancePerRequest();
builder.Register(c => new UserStore<ApplicationUser>(c.Resolve<MyApplicationContext>())).AsImplementedInterfaces().InstancePerRequest();
builder.Register(c => HttpContext.Current.GetOwinContext().Authentication).As<IAuthenticationManager>();
builder.Register(c => new IdentityFactoryOptions<ApplicationUserManager>
{
DataProtectionProvider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider("Application")
});
For reference here's how you can wire everything up using Unity:
var container = new UnityContainer();
container.RegisterType<MyDbContext>(new InjectionConstructor("ConnectionStringName"));
container.RegisterType<IAuthenticationManager>(
new InjectionFactory(c => HttpContext.Current.GetOwinContext().Authentication));
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(
new InjectionConstructor(typeof(MyDbContext)));
container.RegisterType<IRoleStore<IdentityRole, string>, RoleStore<IdentityRole>>(
new InjectionConstructor(typeof(MyDbContext)));
container.RegisterType<IdentityFactoryOptions<ApplicationUserManager>>(new InjectionFactory(x =>
new IdentityFactoryOptions<ApplicationUserManager>
{
DataProtectionProvider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider("ApplicationName")
}));
container.RegisterType<ApplicationSignInManager>();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
Now detailed for MVC5 Owin integration on Autofac Docs:
"
Do all the stuff for standard MVC integration - register controllers, set the dependency resolver, etc.
Set up your app with the base Autofac OWIN integration.
Add a reference to the Autofac.Mvc5.Owin NuGet package.
In your application startup class, register the Autofac MVC middleware after registering the base Autofac middleware.
public class Startup
{
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
// STANDARD MVC SETUP:
// Register your MVC controllers.
builder.RegisterControllers(typeof(MvcApplication).Assembly);
// Run other optional steps, like registering model binders,
// web abstractions, etc., then set the dependency resolver
// to be Autofac.
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
// OWIN MVC SETUP:
// Register the Autofac middleware FIRST, then the Autofac MVC middleware.
app.UseAutofacMiddleware(container);
app.UseAutofacMvc();
}
}
"
I also have RoleManager wrapper so added:
builder.RegisterType<RoleStore<IdentityRole>>().As<IRoleStore<IdentityRole, string>>();
as per SO answer
I managed the workaround by using autofac service locator:
app.CreatePerOwinContext(() => DependencyResolver.Current.GetService<ApplicationUserManager>());
Yes, it is not good enough, but in the mean time, we could use object same scope as declared in autofac registration process.
I try to separate one of my API projects into three different layers.
The API
Data access(repos + uow)
Data Entities
The API is using Asp.net Identity 2.0 with code from a sample I installed, just enough to work with OAuth Authorization.
However, When I do this separation, sometimes I get an error telling me that I need to reference the third layer(entities) from my first layer. And I can't figure out why. That would break the whole purpose of the separation, right?
For example, when I try to replace this line(from the API layer in Startup.Auth.cs, ConfigureAuth method)
app.CreatePerOwinContext(ApplicationDbContext.Create);
With
app.CreatePerOwinContext(uow.CreateDbContext())
A method that returns a new instance of the ApplicationDbContext.
I would expect that context to be returned from my second layer, where my UnitOfWork is(which in turn gets the ApplicationDbContext from the data layer).
Could someone please explain how this works?
To solve your issue you need to start use Interfaces and any DI-framework. Here I can provide you with the code if you want to start using AutoFac (https://code.google.com/p/autofac/wiki/WebApiIntegration).
When you installed AutoFac to your solution through Nuget. Add this part of code in your Global.asax.cs file.
protected void Application_Start()
{
...
SetupAutoFac();
...
}
private static void SetupAutoFac()
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
var container = builder.Setup();
var resolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
}
Create this part of code in your BLL-layer:
public static class AutoFacConfiguration
{
public static IContainer Setup(this ContainerBuilder builder)
{
REGISTER ALL YOUR SERVICES AND UOW HERE
return builder.Build();
}
}
After this you can inject every services Interface to your ApiControllers, and the the WebAPi will only have a reference to your BLL-layer or to the layer where you put all your interfaces.
How can I use an existing IoC with SignalR 2.0?
From the tutorial, it seems I need to setup a class to be called from OWIN via an attribute:
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(SignalRChat.Startup))]
namespace SignalRChat
{
public class Startup
{
public void Configuration(IAppBuilder app /*HOW AM I GONNA GET UNITY CONTAINER HERE?*/)
{
var hubConfig = new HubConfiguration()
{
EnableJSONP = true,
EnableDetailedErrors = true,
EnableJavaScriptProxies = true,
Resolver = new SignalRUnityDependencyResolver(container)
};
// Any connection or hub wire up and configuration should go here
app.MapSignalR(hubConfig);
}
}
}
The problem here is that I already have a container, that's boot strapped and there are singleton instances in the container that needs to be shared with the MVC app shared under the same host.
However the trouble here is that unlike before, it doesn't look like I can call the MapSignalR method from my own code. Rather I need to rely on OWIN to do this for me. However OWIN is not aware of the container that I already setup.
What's the best way to resolve this? I have some very crude ideas how to hack a solution together using static variables to hold some of these - but I hate the very thought of it. The code will be brittle and order of operation could easily introduce a subtle bug.
Is there a way to get a hold of the IAppBuilder instance without having OWIN invoke the above method? This way I can control better when SignalR gets initialized and I can pass my own IoC into the configuration.
In my case I have created a custom hub activator which uses a shared container between my app and signalR (by constructor injection) that way you´ll have single composite root for the whole application.
try the following:
public class CustomHubActivator : IHubActivator
{
private readonly Container _container;
public MseHubActivator(Container container)
{
_container = container;
}
public IHub Create(HubDescriptor descriptor)
{
return _container.GetInstance(descriptor.HubType) as IHub;
}
}
register your custom hub activator when you´re bootstrapping your app (maybe the global.asax)
GlobalHost.DependencyResolver.Register(typeof (IHubActivator),
() => new CustomHubActivator(Container));
that´s much simplier solution rather than to configure again the signalR dependencyResolver
I'm building an ASP.NET MVC4 app. I'm not using any mocking framework and, if possible, would prefer not to at this point. My question is 2 parts.
I have a controller that uses a variable created in Global.asax. In the controller I access the variable like this.
HttpContext.Application["MyVar"]
1) Is this a best-practice for application wide variable usage? If not, what's the best way?
In an attempt to unit test this controller I added the following code (from here) to my test method.
MyController target = new MyController();
var request = new HttpRequest("", "http://example.com/", "");
var response = new HttpResponse(System.IO.TextWriter.Null);
var httpContext = new HttpContextWrapper(new HttpContext(request, response));
target.ControllerContext = new ControllerContext(httpContext, new RouteData(), target);
target.ControllerContext.HttpContext.Application["MyVar"] = new MyVar();
The problem is I can't add anything to Application. The last line of code doesn't seem to do anything and the collection remains empty. I've also tried this in VS's Immediate Window without success.
2) In the unit test, how can I add the application level variables the controller needs?
In general globals aren't good for testing. There are at least two approaches you could take.
Use a mocking framework like Pex/Moles, NMock, etc.
Use an inversion-of-control approach (NInject is my favorite). If class like a controller has an external dependency, it asks for the interface, typically in its constructor.
private readonly IApplicationSettings _settings;
public MyController(IApplicationSettings settings)
{
_settings = settings;
}
void someMethod()
{
_settings.Get("MyVar");
}
This way you can write real and test implementations.
public LiveAppSettings : IApplicationSettings
{
public string Get(string key)
{
return HttpContext.Current.Application[key];
}
}
With Ninject, you can bind either implementation at application startup:
var kernel = new StandardKernel();
kernel.Bind<IApplicationSettings>().To<LiveAppSettings>();
Is this a best-practice for application wide variable usage?
Best practice is a bit of a subjective notion and without fully explaining your scenario and what precisely are you trying to achieve I prefer not to discuss it.
We cannot discuss whether this is best practice but from what I can see it is not wrong either. It is not wrong because you are using the abstractions allowing the code to be unit tested.
In the unit test, how can I add the application level variables the controller needs?
You could use a mocking framework such as Rhino Mocks to mock the abstractions that the controller needs. Let's take as an example the following controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var myVar = (MyVar)HttpContext.Application["MyVar"];
return Content(myVar.Foo);
}
}
and we would like to unit test the Index action. Here's a sample unit test:
[TestMethod]
public void Index_Action_Should_Retrieve_MyVal_From_AppState()
{
// arrange
var target = new HomeController();
var httpContext = MockRepository.GeneratePartialMock<HttpContextBase>();
var application = MockRepository.GeneratePartialMock<HttpApplicationStateBase>();
application.Expect(x => x["MyVar"]).Return(new MyVar { Foo = "bar" });
httpContext.Expect(x => x.Application).Return(application);
target.ControllerContext = new ControllerContext(httpContext, new RouteData(), target);
// act
var actual = target.Index() as ContentResult;
// assert
Assert.AreEqual("bar", actual.Content);
}