how to inject dependency in _viewimports file - asp.net

I am trying to generate a generic BaseViewPage in asp.net Core to access Current User's Identities.
For this purpose I created a BaseViewPage.cs file -
public abstract class BaseViewPage<TModel> : RazorPage<TModel>
{
private static ClaimsPrincipal principal;
public BaseViewPage(IPrincipal _principal)
{
principal = _principal as ClaimsPrincipal;
}
}
As you can see in the constructor here I am injecting a dependency of IPrincipal type so that it gets defined at run time.
Now time to inherit it in _viewimports.cshtml file to use current user in all the view pages as below -
#using TWCStore
#inherits MyStore.Helpers.BaseViewPage<TModel>
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Whenever I try to use any property in my view - ProductCategories.cshtml the error invokes here
Severity Code Description Project File Line Suppression State
Error CS7036 There is no argument given that corresponds to the
required formal parameter '_principal' of
'BaseViewPage.BaseViewPage(IPrincipal)' MyStore D:\Projects\TWCStore\TWCStore\Views\Store\ProductCategories.cshtml 1 Active
I am assuming when I am injecting the dependency then it wants me to put the IPrincipal as Dependency here too -
#inherits MyStore.Helpers.BaseViewPage<TModel>
How do I inject this dependency in here ?

Its late I am writing solution (actually an alternate) to this problem here.
So I followed dependency injection (sorry for now forgetting the help link).
Here is what I did -
Create an Interface
public interface IAppUserAccessor
{
int MemberId { get; }
}
Resolver class
public class AppUserAccessor : IAppUserAccessor
{
private readonly MyContext _context;
public AppUserAccessor(MyContext context)
{
_context = context;
}
int IAppUserAccessor.MemberId
{
get
{
return _context.Member.MemberId;
}
}
}
Register the service in StartUp.cs under 'ConfigureServices' section
services.AddTransient<IAppUserAccessor, AppUserAccessor>();
Inject in _viewimports.cshtml
#using MyApplication
#inject MyApplication.Helpers.IAppUserAccessor AppUserAccessor
Now this is accessible in every view as -
#AppUserAccessor.MemberId

Related

ASP.NET Unity.MVC DI with EF context

I'm using Unity.MVC for DI in my ASP.NET MVC 4.6 app. I have a service interface passed into the controller and that's working great. Now I want to pass in an interface to the EF context to the service but I'm not sure how to do this. I've read EF has this IObjectContextAdapter that I could pass into my service ctor and that works, but I need to then query the actual tables on inside my service from this context but because it's an IObjectContextAdapter it doesn't know my tables. How do I do this?
public class ContactService : IContactService
{
//private ContactsEntities context;
private IObjectContextAdapter context;
// test ctor
public ContactService(IObjectContextAdapter ctx)
{
context = ctx;
}
// prod ctor
public ContactService()
{
context = new ContactsEntities();
}
List<Contact> GetAllContacts()
{
return (from c in context.ObjectContext.?? // I need to query the Contacts table that would be attached to the actual context I pass in but still keep the decoupling from using an Interface passed into the ctor
}
}
The IObjectContextAdapter is the type of ObjectContext property of DbContext.
You should subclass DbContext e.g. ContactsDatabaseContext
public class ContactsDatabaseContext : DbContext, IContactsDatabaseContext
{
// ...
}
And then just register your ContactsDatabaseContext with your IoC container. Something like this:
container.RegisterType<IContactsDatabaseContext, ContactsDatabaseContext>();
Your ContactsDatabaseContext class and IContactsDatabaseContext interface should have properties of type DbSet<T> that refer to your tables e.g.:
IDbSet<BrandDb> Users { get; set; }
UPDATE:
Since you are using a generated file, then do this:
public partial class ContactsDatabaseContext : IContactsDatabaseContext
{
// Expose the DbSets you want to use in your services
}

MVC 6 #inherit RazorPage

I am trying to migrate an MVC 5 Application to ASP.NET 5 MVC 6 (Beta 7).
Having problems when using the #inherits and #model directive together.
Works fine when they are used separately.
In my _ViewImports i added the #inherits directive to use a base page with some custom user properties.
public abstract class BaseViewPage<TModel> : RazorPage<TModel>
{
protected MyPrincipal AppUser
{
get
{
return new MyPrincipal(this.User as ClaimsPrincipal);
}
}
}
_ViewImports.cshttml
#inherits CommonWeb.BaseViewPage<TModel>
#addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"
And then i can go AppUser. in all my views.
This works if i dont use a strongly typed view. If i add the #model directive in any view the inherited view page goes away.
Help appreciated
Update:
I did this successfully by using a custom pageBaseType in the web.config in prior versions.
Workaround.
public class ViewHelper
{
ViewContext _context;
public ViewHelper(ViewContext context)
{
_context = context;
}
public MyPrincipal AppUser
{
get
{
return new MyPrincipal(_context.HttpContext.User as ClaimsPrincipal);
}
}
public string ControllerName
{
get
{
return _context.RouteData.Values["controller"].ToString();
}
}
}
View:
#{ var viewHelper = new ViewHelper(ViewContext);}
A way to achieve this for all views?
There is a better way in MVC 6, which now supports injecting dependencies on the views with the #inject directive. (The directive #inject IFoo Foo allows you to use in your view a property named Foo of type IFoo)
Create a new interface IAppUserAccessor for getting your app user, for example:
public interface IAppUserAccessor
{
MyPrincipal GetAppUser();
}
Create a class AppUserAccessor implementing it:
public class AppUserAccessor : IAppUserAccessor
{
private IHttpContextAccessor httpContextProvider;
public AppUserAccessor(IHttpContextAccessor httpContextProvider)
{
this.httpContextProvider = httpContextProvider;
}
public MyPrincipal GetAppUser()
{
return new MyPrincipal (
httpContextProvider.HttpContext.User as ClaimsPrincipal);
}
}
Register the new interface in the services container by adding a new entry in the ConfigureServices method of Startup.cs:
services.AddTransient<IAppUserAccessor, AppUserAccessor>();
Finally use the #inject directive to inject the IAppUserAccessor in your views. If you add the directive in ViewImports.cshtml then it will be available on every view.
#inject WebApplication4.Services.IAppUserAccessor AppUserAccessor
With all the pieces above you can now just use it on your view(s):
#AppUserAccessor.GetAppUser()
Update
If you need to inspect the route values, like the controller name, you can inject an IActionContextAccessor into your class and use it as follows:
public AppUserAccessor(IHttpContextAccessor httpContextProvider, IActionContextAccessor actionContextAccessor)
{
this.httpContextProvider = httpContextProvider;
this.actionContextAccessor = actionContextAccessor;
}
...
public string ControllerName
{
get { return actionContextAccessor.ActionContext.RouteData.Values["controller"].ToString(); }
}
Of course, that doesn't look like an AppUserAccessor anymore and smells like it has different responsabilities. At the very least it needs a more appropriate name :)
I would double check what do I need the controller name for. There might be a better way to accomplish your objective. (For example, if you need it for generating new links/urls you might just use an IUrlHelper)
Accessing ViewContext
Looks like beta8 has added support for injecting the ViewContext, although the implementation details may change before RC. See this question

Registration by convention and interception causes ResolutionFailedException

Simple scenario
public interface IFoo
{
int GetData();
}
public class Foo : IFoo
{
[CacheResult]
public int GetData() { .... }
}
public class MyController
{
[Dependency]
IFoo Foo {get; set;}
}
If I register the interface manually, resolving MyController works fine:
container.RegisterType<IFoo, Foo>(new ContainerControlledLifetimeManager(),
new InterceptionBehavior<PolicyInjectionBehavior>(),
new Interceptor<InterfaceInterceptor>());
var controller = container.Resolve<MyController>();
If I try to use auto-registration:
container.RegisterTypes(
AllClasses.FromLoadedAssemblies(),
WithMappings.FromMatchingInterface,
WithName.Default,
WithLifetime.ContainerControlled,
getInjectionMembers: t => new InjectionMember[]
{
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior<PolicyInjectionBehavior>(),
});
var controller = container.Resolve<MyController>();
The resolve fails with a ResolutionFailedException because the Type passed must be an interface. Of course, if I make it an interface, it will work, but only if it is named Controller. If I call it, MyController or SqlController or whatever, then the mapping fails because it cannot resolve the interface.
I was hoping to just do an assembly scan, similar to what the Spring framework does, but I have not been able to figure it out.
What am I missing? Or is this not possible in Unity?
The problem is that AllClasses.FromLoadedAssemblies is matching and registering your controller as well. Then when Unity tries to resolve the controller (not IFoo), it finds that the controller is not registered with an interface.
Here's a helper that will reduce your registrations to only those classes that have a matching interface.
public static class TypeFilters
{
public static IEnumerable<Type> WithMatchingInterface(this IEnumerable<Type> types)
{
return types.Where(type =>
type.GetTypeInfo().GetInterface("I" + type.Name) != null);
}
}
and then you can use this to modify your registration like so...
AllClasses.FromLoadedAssemblies().WithMatchingInterface()

strucutreMap Dependency injection is not working

In my application i configured structuremap like
public class DefaultRegistry : Registry {
#region Constructors and Destructors
public DefaultRegistry() {
Scan(
scan => {
scan.Assembly("Eterp.Data.ErpCore");
scan.Assembly("Eterp.Data.Seed");
scan.Assembly("Eterp.Application.ErpCore");
scan.TheCallingAssembly();
scan.WithDefaultConventions();
});
ForConcreteType<AclAuthorizationManager>().Configure.Ctor<IResourceOperationAppService>()
}
#endregion
}
And i have class
public class AclAuthorizationManager : ClaimsAuthorizationManager
{
private readonly IResourceOperationAppService _resourceOperationAppService;
public AclAuthorizationManager(IResourceOperationAppService resourceOperationAppService)
{
_resourceOperationAppService = resourceOperationAppService;
}
public override bool CheckAccess(AuthorizationContext context)
{
var isCurrentUserAuthorized = context.Principal.Identity.IsAuthenticated;
return isCurrentUserAuthorized && _resourceOperationAppService.CanAccessResource(context.Action.FirstOrDefault().Value, context.Principal.Claims);
}
}
This class is custom claim authorization class using in my application, but when i exceuting the application,i am getting an error which related to lack of parameter required by the constructor, ( This class has constructor with parameter type IResourceOperation). but i already configured all the details in structureMap . i am sure that my structuremap configuration is working 100% well expect the creation of this AclAuthorizationManager class.because i am able to to apply DI in other classes.
What is wrong part in my code?
in my experience when you specify the type constructor must say that inherits from the interface.
Therefore, you should replace this line:
ForConcreteType<AclAuthorizationManager>().Configure.Ctor<IResourceOperationAppService>()
By:
ForConcreteType<AclAuthorizationManager>().Configure.Ctor<IResourceOperationAppService>().Is<ResourceOperationAppService>()
Where is the implementation ResourceOperationAppService IResourceOperationAppService.

How can you inject an asp.net (mvc2) custom membership provider using Ninject?

OK, so I've been working on this for hours. I've found a couple of posts here, but nothing that actually resolves the problem. So, let me try it again...
I have an MVC2 app using Ninject and a custom membership provider.
If I try and inject the provider using the ctor, I get an error: 'No parameterless constructor defined for this object.'
public class MyMembershipProvider : MembershipProvider
{
IMyRepository _repository;
public MyMembershipProvider(IMyRepository repository)
{
_repository = repository;
}
I've also been playing around with factories and Initialize(), but everything is coming up blanks.
Any thoughts/examples?
The Membership provider model can only instantiate a configured provider when it has a default constructor. You might try this using the Service Locator pattern, instead of using Dependency Injection. Example:
public class MyMembershipProvider : MembershipProvider
{
IMyRepository _repository;
public MyMembershipProvider()
{
// This example uses the Common Service Locator as IoC facade, but
// you can change this to call NInject directly if you wish.
_repository = ServiceLocator.Current.GetInstance<IMyRepository>;
}
This is how I was able to do this:
1) I created a static helper class for Ninject
public static class NinjectHelper
{
public static readonly IKernel Kernel = new StandardKernel(new FooServices());
private class FooServices : NinjectModule
{
public override void Load()
{
Bind<IFooRepository>()
.To<EntityFooRepository>()
.WithConstructorArgument("connectionString",
ConfigurationManager.ConnectionStrings["FooDb"].ConnectionString);
}
}
}
2) Here is my Membership override:
public class FooMembershipProvider : MembershipProvider
{
private IFooRepository _FooRepository;
public FooMembershipProvider()
{
NinjectHelper.Kernel.Inject(this);
}
[Inject]
public IFooRepository Repository
{
set
{
_FooRepository = value;
}
}
...
With this approach it doesn't really matter when the Membership provider is instantiated.
I had the same problem at the exact same spot in the book. It wasn't until later on in the book that I noticed there were two separate web.config files. I initially placed my connectionString key in the wrong web.config file. It wasn't until I placed the connectionString in the correct web.config file that the 'no parameterless constructor' error went away.

Resources