IoC container implementation in controller - c#

I want to use the IoC container in a method to check a logged in users company code when they submit a payment. I have two certificates in my settings class and an IF else statement to differentiate between each one.
public static string FDGCreditCardUserID
{
get
{
if (BillingController.currentcompanycode == 5)
return ConfigurationManager.AppSettings["5FDGCreditCardUserID"];
else
return ConfigurationManager.AppSettings["6FDGCreditCardUserID"];
}
}
public static string FDGCreditCardPassword
{
get
{
if (BillingController.currentcompanycode == 5)
return ConfigurationManager.AppSettings["5FDGCreditCardPassword"];
else
return ConfigurationManager.AppSettings["6FDGCreditCardPassword"];
}
}
Then in my IoC container
x.For<IFDGService>().Use<FDGService>().SetProperty(s =>
{
s.Url = Settings.FDGURL;
s.UserID = Settings.FDGCreditCardUserID;
s.Password = Settings.FDGCreditCardPassword;
s.Certificate = Settings.FDGCreditCardCertFilePath;
});
I have an FDGService that checks credentials but does not return to the IoC on payment submit to check the company code and apply the correct certificate.
SubmitPayment Method where the creditcard control contains the correct company code when i run it.
How do i get my application to select the correct certificate based on the updated company code. Seeing as users can have different company codes based on policies selected for payment. One company code at the moment can either be 5 or 6.
public ActionResult SubmitPayment([ConvertJSON]List<PayModel> payments)
{
List<TransactionModel> transactions = new List<TransactionModel>();
foreach (var pymt in payments)
{
var policyNumber = pymt.PolicyNumber.Trim();
TransactionModel trans = new TransactionModel() { Payment = pymt };
if (pymt.Selected)
{
var creditCardControl = UpdateCreditCardControl(policyNumber);

If you are using StructureMap it uses "Greedy Initialization", meaning when the constructor is called it will call the constructor with the most amount of arguments or parameters passed in.
private IFDGService service;
public MyController(IFDGService service)
{
this.service = service;
}
Then service will be available after IoC.Configure() is called.
Call IoC.Configure() whereever the application is started. google "where does Mvc start" or something like that.
to change the company code set it somewhere other than an instance variable in the controller, like a static class, I know static is bad, get it working and then make it better, since that would be complex to modify, and then get; set; when you need to.
I have to go to meeting, kinda rushed, hope that helps

Related

Inject User Credentials from HttpRequestContext into the service layer

I have a .NET 4.6 WebApi 2.0 OWIN App that serves HTTP Requests.
Those requests are authenticated and we are storing certain claims in the RequestContext ClaimsIdentity (UserId, Client Code)
We also have our Controllers, Services and Repository structure.
Our Services are injected into the Controllers via Ninject, and the Repositories into the Services.
When the user performers certain requests we need to check their permissions. The service usually needs to know the: UserId, ClientCode, Groups the user has access to and permissions under each group (Read, Write, etc). This last one is only being stored in a DataBase.
The current flow when executing a request is: obtain the userId and clientCode from the RequestContext claims, use that userid to obtain the Group permissions from the DataBase. Create an object UserCredentials with those properies.
This object is then passed on to the Service instances after they were injected
This is an example:
public PeopleController(IPeopleService peopleService, IUserManagementService userManagementService)
{
var clientCode = RequestContext.GetClientCode();
var userId = RequestContext.GetUserId();
var permissions = userManagementService.GetUserPermissions(userId, clientCode);
}
peopleService.InjectCredentials(new services.Models.UserCredentials()
{
ClientCode = clientCode,
UserId = UserId,
Permissions = UserPermissions
});
_peopleService = peopleService;
}
This doesn't look very elegant to us as we need to repeat that code everywhere and makes the IPeopleService dependant that the user doesn't forget to call the InjectCredentials method.
So my question is, how can I make that UserCredentials class Injectable so it can be passed as a parameter to the IPeopleService constructor?
The main block is that it depends on the HttpRequestContext which is only available on the Controller itself
Thanks
EDIT: I know UserCredentials object can be also be passed as a parameter to each service Method (which is actually better than the InjectCredentials method)
Instead of Injecting the Model,
In your IUserManagementService implementation inject IHttpContextAccessor. Then implement a method to do what you would do in the controller.
Let this method be responsible for fetching user details for you.
public class UserManagementService : IUserManagementService
{
private readonly IHttpContext httpContext;
public UserManagementService (IHttpContext httpContext)
{
this.httpContext = httpContext;
}
public UserCredentials GetUserDetails()
{
new services.Models.UserCredentials()
{
ClientCode = clientCode,
UserId = UserId,
Permissions = UserPermissions
});
}
}
Finally, inject this service in any other service where you need these details.
PeopleController(IPeopleService peopleService, IUserManagementService userManagementService)
I found one way that is possible, but I don't think its recommended due to the use of HttpContext.Current.user
kernel.Bind<UserCredentials>().ToMethod(CreateUserCredentials);
private static UserCredentials CreateUserCredentials(IContext arg)
{
var identity = HttpContext.Current.User as ClaimsPrincipal;
int userId = identity.Identity.GetUserId();
string clientCode = identity.Identity.GetClientCode();
var userManagementService = kernel.Get<IUserManagementService>();
if (userId != 0)
{
var permisssions = userManagementService.GetUserPermissions(userId, userType, clientCode);
}
return new UserCredentials()
{
ClientCode = clientCode,
UserId = userId,
Permissions = userManagementService.GetUserPermissions(userId, clientCode)
};
}
Now the UserCredentials object can be added to constructors as a parameter and will properly intialised.

How should I handle NotFound 404 having services and not only simple repositories

All samples about Web API and return Resource states on the server look like this:
var resource = repository.Get(id);
if(resource == null)
{
return NotFound();
}
return resource;
This works in the most simple architectures.
But having much business logic and services calling that repositories I do not see how I can still use this approach.
In our architecture every web api controller gets a service injected and each service gets one or many repositories or even other services injected.
Now my services do not have simple Get methods returning a resource.
These services could look like:
action(string materialNumber)
{
var pdf = service.CreateProductPDF(materialNumber);
return pdf;
}
class Service
{
public XXX CreateProductPDF(string materialNumber)
{
// Do repository call here but HOW do I let the action know that the materialNumber does not exist?
// Create product pdf from materialNumber
}
}
My question is inside the comment above.
Your domain should be able to transport a value object from the repository to service.
That value object can be called DomainResult and it should contain both the domain objects you're requesting along with domain validation information (i.e. broken rules).
For example:
// It's an OVERSIMPLIFICATION, but it should give you the hint
// to keep you in the right track...
// This code requires C# 6 as it's using expression-bodied properties!
public class DomainResult<TResult>
{
public TResult Result { get; set; }
public List<BrokenRule> BrokenRules { get; } = new List<BrokenRule>();
public bool IsSuccessful => BrokenRules.Count == 0;
}
For example, your method might look like this:
class Service
{
public DomainResult<PdfDocument> CreateProductPDF(string materialNumber)
{
DomainResult<PdfDocument> result = repo...;
// result object might contain a BrokenRule containing a code/message
// "Product couldn't be created because materialNumber wasn't found"
return result;
}
}
And then you can return a 404 in your Web API resource method depending on which rules have been broken during the domain transaction. Also, you should add these broken rule messages to the ModelState using ModelState.AddModelError within your API controller.

Using the subdomain as a parameter

I’ve got an ASP.net MVC (5.2) site that runs using several subdomains, where the name of the subdomain is the name of a client in my database. Basically what I want to do is use the subdomain as a variable within my action methods to allow me to get the correct data from my database.
I did something similar a few years back, but it’s messy and not intuitive, so was wondering if there’s a better way to do it than I was using before. Here’s what I did before:
protected override void OnActionExecuting(ActionExecutingContext filterContext) {
Session["subdomain"] = GetSubDomain(Request.Url);
}
private static string GetSubDomain(Uri url) {
string host = url.Host;
if (host.Split('.').Length > 1) {
int index = host.IndexOf(".");
string subdomain = host.Substring(0, index);
if (subdomain != "www") {
return subdomain;
}
}
return null;
}
Which basically assigned a key to the session variable if the subdomain was anything other than "www", but I’m really not happy with this way of doing it as it relies on me knowing that the session might contain this magic value!
Ideally I’d like to be able to create an attribute that I can decorate my classes/methods with that would extract the subdomain and then allow me to include a "subdomain" parameter in my action method that would contain the value extracted by the attribute. Is that even possible?
If that can’t be done, is there a better way of doing what I’m doing now without having to rely on the session?
Thanks,
Dylan
Your right this doesn't need to be stored in Session and IMHO shouldn't be, I would refactor this out into its own class and use HttpContext.Current.
public interface ISubDomainProvider
{
string SubDomain { get; set; }
}
public class SubDomainProvider : ISubDomainProvider
{
public SubDomainProvider()
{
string host = HttpContext.Current.Request.Url.Host; // not checked (off the top of my head
if (host.Split('.').Length > 1)
{
int index = host.IndexOf(".");
string subdomain = host.Substring(0, index);
if (subdomain != "www")
{
SubDomain = subdomain;
}
}
}
public string SubDomain { get; set; }
}
You choose how to use it, if your using an IoC container it would just be a case of injecting this class into your controller via the constructor, I like this because it is easier to Mock and Unit Test. Of course you can still do this:
public class SomeController : Controller
{
private readonly ISubDomainProvider _subDomainProvider;
public SomeController()
{
_subDomainProvider = new SubDomainProvider();
}
}
You could even create you own abstract Controller Class:
public abstract class MyAbstractController : Controller
{
public MyAbstractController()
{
SubDomain = new SubDomainProvider();
}
protected string SubDomain {get; set; }
}
public class SomeController : MyAbstractController
{
public ActionResult SomeAction()
{
// access the subdomain by calling the base base.SubDomain
}
}
You could set the name in the Session on the Session_Start event in the global.asax, this means it would only happen one time and would persist for the duration of the users' session
public void Session_Start(object sender, EventArgs e)
{
Session["subdomain"] = GetSubDomain(Request.Url);
}
Looks like there’s a good way of doing what I’m after at:
ASP.NET MVC Pass object from Custom Action Filter to Action
It essentially uses the route data to pass a custom parameter to the action, and can also pass objects other than simple strings etc.
On the plus side it avoids using the session and relying on magic values, but on the downside it means processing the URL for every request, which probably isn’t a good idea if a database is involved.

Null User on HttpContext obtained from StructureMap

Ok, my previous question/setup had too many variables, so I'm stripping this down to it's bare bones components.
Given the code below using StructureMap3...
//IoC setup
For<HttpContextBase>().UseSpecial(x => x.ConstructedBy(y => HttpContext.Current != null ? new HttpContextWrapper(HttpContext.Current) : null ));
For<ICurrentUser>().Use<CurrentUser>();
//Classes used
public class CurrentUser : ICurrentUser
{
public CurrentUser(HttpContextBase httpContext)
{
if (httpContext == null) return;
if (httpContext.User == null) return;
var user = httpContext.User;
if (!user.Identity.IsAuthenticated) return;
UserId = httpContext.User.GetIdentityId().GetValueOrDefault();
UserName = httpContext.User.Identity.Name;
}
public Guid UserId { get; set; }
public string UserName { get; set; }
}
public static class ClaimsExtensionMethods
public static Guid? GetIdentityId(this IPrincipal principal)
{
//Account for possible nulls
var claimsPrincipal = principal as ClaimsPrincipal;
if (claimsPrincipal == null)
return null;
var claimsIdentity = claimsPrincipal.Identity as ClaimsIdentity;
if (claimsIdentity == null)
return null;
var claim = claimsIdentity.FindFirst(x => x.Type == ClaimTypes.NameIdentifier);
if (claim == null)
return null;
//Account for possible invalid value since claim values are strings
Guid? id = null;
try
{
id = Guid.Parse(claim.Value);
}
catch (ArgumentNullException) { }
catch (FormatException) { }
return id;
}
}
How is this possible in the Watch window?
I have a web application that I'm upgrading to using StructureMap 3.x from 2.x, but I'm getting odd behavior on specific dependency.
I have a ISecurityService that I use to obtain verify some things when a user requests a page. This service depends on a small interface that I've called ICurrentUser. The class implementation is pretty plain, really it could be a struct.
public interface ICurrentUser
{
Guid UserId { get; }
string UserName { get; }
}
This is obtained via dependency injection using the below code.
For<ICurrentUser>().Use(ctx => getCurrentUser(ctx.GetInstance<HttpContextBase>()));
For<HttpContextBase>().Use(() => getHttpContext());
private HttpContextBase getHttpContext()
{
return new HttpContextWrapper(HttpContext.Current);
}
private ICurrentUser getCurrentUser(HttpContextBase httpContext)
{
if (httpContext == null) return null;
if (httpContext.User == null) return null; // <---
var user = httpContext.User;
if (!user.Identity.IsAuthenticated) return null;
var personId = user.GetIdentityId().GetValueOrDefault();
return new CurrentUser(personId, ClaimsPrincipal.Current.Identity.Name);
}
When a request comes in, my site wide authentication happens first, which depends on ISecurityService. This happens inside of OWIN and appears to occur before HttpContext.User has been populated, so it's null, so be it.
Later on, I have an ActionFilter that checks, via a ISecurityService, if the current user has agreed to the current version of the TermsOfUse for the site, if not they are redirected to the page to agree to them first.
This all worked fine in structuremap 2.x. For my migration to StructureMap3 I've installed the Nuget package StructureMap.MVC5 to help speed things up for me.
When my code gets to the line in my ActionFilter for checking the terms of use I have this.
var securityService = DependencyResolver.Current.GetService<ISecurityService>();
agreed = securityService.CheckLoginAgreedToTermsOfUse();
Inside of CheckLoginAgreedToTermsOfUse(), my instance of CurrentUser is null. Even though it would hazve succeeded, and my breakpoint inside of getCurrentUser() never seems to be hit. Its almost as if it's a foregone conclusion, since it was null the last time , even though it would have resolved this time.
I'm kind of baffled as to why getCurrentUser() is never called on the request for ISecurityService. I even tried explicitly sticking a .LifecycleIs<UniquePerRequestLifecycle>() on my hookup for handling ICurrentUser with no effect.
UPDATE:
Ok so just a heads up, I've started using the method accepted below, and while it has worked great so far, it didn't resolve my core problem. Turns out the new StructureMap.MVC5, based on StructureMap3, uses NestedContainers. Which scope their requests to the lifetime of the NestedContainer, regardless of the default being Transient. So when I requested HttpContextBase for the first time, it will then return that same instance for the rest of the request (even though later on in the request lifespan, the context has changed. You need to either not use NestedContainer (which, as I understand it will complicate things ASP.NET vNext), or you explicitly set the lifecycle of the For<>().Use<>() mapping to give you a new instance per request. Note that this scoping per NestedContainer causes problems with Controllers as well in MVC. While the StructureMap.MVC5 package handles this with a ControllerConvention, it does not handle Views, and recursive views or views used multiple times will likely cause you problems as well. I'm still looking for a permanent fix for the Views problem, for the moment I've reverted to the DefaultContainer.
I haven't worked with OWIN, but when hosting in IIS integrated mode the HttpContext is not populated until after the HttpApplication.Start event is complete. In terms of DI, this means that you cannot rely on using properties of HttpContext in any constructor.
This makes sense if you think about it because the application should be initialized outside of any individual user context.
To get around this, you could inject an abstract factory into your ICurrentUser implementation and to use a Singleton pattern to access it, which guarantees HttpContext won't be accessed until it is populated.
public interface IHttpContextFactory
{
HttpContextBase Create();
}
public class HttpContextFactory
: IHttpContextFactory
{
public virtual HttpContextBase Create()
{
return new HttpContextWrapper(HttpContext.Current);
}
}
public class CurrentUser // : ICurrentUser
{
public CurrentUser(IHttpContextFactory httpContextFactory)
{
// Using a guard clause ensures that if the DI container fails
// to provide the dependency you will get an exception
if (httpContextFactory == null) throw new ArgumentNullException("httpContextFactory");
this.httpContextFactory = httpContextFactory;
}
// Using a readonly variable ensures the value can only be set in the constructor
private readonly IHttpContextFactory httpContextFactory;
private HttpContextBase httpContext = null;
private Guid userId = Guid.Empty;
private string userName = null;
// Singleton pattern to access HTTP context at the right time
private HttpContextBase HttpContext
{
get
{
if (this.httpContext == null)
{
this.httpContext = this.httpContextFactory.Create();
}
return this.httpContext;
}
}
public Guid UserId
{
get
{
var user = this.HttpContext.User;
if (this.userId == Guid.Empty && user != null && user.Identity.IsAuthenticated)
{
this.userId = user.GetIdentityId().GetValueOrDefault();
}
return this.userId;
}
set { this.userId = value; }
}
public string UserName
{
get
{
var user = this.HttpContext.User;
if (this.userName == null && user != null && user.Identity.IsAuthenticated)
{
this.userName = user.Identity.Name;
}
return this.userName;
}
set { this.userName = value; }
}
}
Personally, I would make the UserId and UserName properties readonly, which would simplify the design and ensure they don't get hijacked elsewhere in the application. I would also make an IClaimsIdentityRetriever service that is injected into the constructor of ICurrentUser instead of retrieving the claims Id in an extension method. Extension methods go against the grain of DI and are generally only useful for tasks that are guaranteed not to have any dependencies (such as string or sequence manipulation). The loose coupling of making it a service also means you can easily swap or extend the implementation.
Of course, this implies that you cannot call the UserId or UserName properties of your CurrentUser class in any constructor as well. If any other class depends on ICurrentUser, you may also need an ICurrentUserFactory in order to safely use it.
Abstract factory is a lifesaver when dealing with difficult-to-inject dependencies and solves a host of problems including this one.

Entity Framework not refreshing data when using Repository Pattern

I am using the repository and unit of work patterns and dependency injection to access the database with entity framework 5 in my web application. I have a User class from which Entity Framework generates a Code-First database.
public class User
{
public Guid UserId { get; set; }
public string UserName { get; set; }
.
.
.
public string LanguagePreference { get; set; }
public virtual List<Role> Roles { get; set; }
public virtual List<Branch> Branches { get; set; }
}
I have a UserService class that is used to Add or Update users. This class takes an IUserUnitOfWork as a parameter in the constructor and Unity injects a UserUnitOfwork. The IUserUserOfWork contains an IRepository<User>, an IRepository<Location> and an IRepository<Role>. These are set as Repository<T> by the DI bootstrapper. The IUserUnitOfWork sets up the different Repositories with the same entity framework DbContext. I did this as I was having issues updating the many-to-many relationships related to the User (Locations and Roles).
UserUnitOfWork:
public IRepository<Branch> BranchRepository {get; set;}
public IRepository<Role> RoleRepository { get; set; }
public IRepository<User> UserRepository { get; set; }
public DbContext Context { get; set; }
public UserUnitOfWork(DbContext context, ITransientErrorDetectionStrategy errorDetectionStrategy,RetryStrategy retryStrategy )
{
Context = context;
BranchRepository = new Repository<Branch>(context, errorDetectionStrategy, retryStrategy);
RoleRepository = new Repository<Role>(context, errorDetectionStrategy, retryStrategy);
UserRepository = new Repository<User>(context, errorDetectionStrategy, retryStrategy);
}
The Repository class then uses Entity Framework 5 to access the database.
Example of method from Repository.FirstOrDefault:
public virtual T FirstOrDefault(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = "")
{
T result = null;
_retryPolicy.ExecuteAction(() =>
{
IQueryable<T> entities = GetHelper(filter, orderBy, includeProperties);
result = entities.FirstOrDefault();
});
return result;
}
And Update from Repository:
public virtual void Update(T entity)
{
if (_dbContext.Entry(entity).State == System.Data.EntityState.Detached)
{
_dbContext.Set<T>().Attach(entity);
_dbContext.Entry(entity).State = System.Data.EntityState.Modified;
}
}
So my problem now is that when I update the User it correctly updates the data in the database, and when I log out and log in the initial change works. However if I update again and log out and in the new change isn't picked up even though the database is updated.
I'm beginning to fear that the approach I've taken is incorrect, can someone tell me how to make sure that when I do an update Entity Framework will always get the latest version?
EDIT:
So I've created a Per Request Lifetime Manager like so:
public class PerHttpRequestLifetimeManager : LifetimeManager
{
private readonly object key = new object();
public override object GetValue()
{
if (HttpContext.Current != null &&
HttpContext.Current.Items.Contains(key))
return HttpContext.Current.Items[key];
else
return null;
}
public override void RemoveValue()
{
if (HttpContext.Current != null)
HttpContext.Current.Items.Remove(key);
}
public override void SetValue(object newValue)
{
if (HttpContext.Current != null)
HttpContext.Current.Items[key] = newValue;
}
}
In my DI bootstrapper I now setup my domain context like below:
container.RegisterType<DbContext, DomainContext>(new PerHttpRequestLifetimeManager());
It still doesn't appear to be working, am I missing something else or am I setting it up incorrectly?
EDIT 2:
Just to point out the architecture:
We have an MVC application which uses Angular JS to make ajax calls to a Web Api service layer. The Web Api has an ISomethingService injected into it. It is this ISomethingService that has the repositories injected into it. Would there be some confusion for the PerHttpRequestLifetimeManager since there is both an MVC and Web API project running?
EDIT 3:
An example of how I am saving the edited user:
We have a UserModel class that is used for communications between the ServiceLayer -> API -> UI layer and back. The User class is the one generated by Entity Framework code first. The EditUser method in the UserService takes in a UserModel.
I then user the _unitOfWork.UserRepository to get the corresponding database user
var editedUser = _unitOfWork.UserRepository.FirstOrDefault(x => x.UserId == userModel.UserId);
I map the fields from the userModel to the editedUser and I then call (in the UserService)
_unitOfWork.UserRepository.Update(editedUser)
and after
_unitOfWork.Save()
YET ANOTHER EDIT:
So I have edited a simple method that updates a single text field on the user table (Language Preference). I explicitly call the dispose method after the update to ensure I am disposing the method.
public void SetUserLanguagePreference(Guid userId, string language)
{
var user = _unitOfWork.UserRepository.FirstOrDefault(x => x.UserId == userId);
user.LanguagePreference = language;
_unitOfWork.UserRepository.Update(user);
_unitOfWork.Save();
_unitOfWork.Dispose();
}
UnitOfWork.Dispose() calls the dispose method of the repositories and the Dbcontext
The database updates correctly. However the behaviour is still incorrect. When I log out and in first it retrieves the correct value. When I change it again and log out and in again it doesn't update. This has been the pattern before, it get the first update after I log out and in, but if I change again and log out and in it doesn't pick it up.
Finally, not an edit but an answer! We use Claims based authentication and have a class that overrides the ClaimsPrinciple Authenticate method that is called whenever a user is authenticated.
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
if (incomingPrincipal.Identity.IsAuthenticated)
{
//Check here if the authenticated user has access to this system
//using the user repository and if so add more claims to the token
}
return base.Authenticate(resourceName, incomingPrincipal);
}
It was not possible to inject into this method using DI as it always went to the empty constructor (not sure why but that's the way it is).
So instead we were setting the repository in the empty constructor like so:
public PRAuthenticationManager()
{
_userRepository = DiBootstrapper.Container.Resolve<IRepository<User>>();
}
When the Authenticate method is called we check our database for a user with the claims attached to the ClaimsPrincipal. If we make a match we add new claims to the token which are then used for each call to the Web Api later. This repository was not being disposed (even if all the others were) and so when a user logged out and in they got data from that same context which had not been disposed from the last time the user logged in.
Three full days trying to find that one....
See if this helps: How do I get Entity Framework 5 to update stale data
I ran into the same problem, it doesn't refresh from the database if you already have the object in your ObjectContext, of course, this would only work on a per object basis, but that might be just what you need.

Categories

Resources