How to create DbContext - asp.net-core

below default code in controller working fine
public ProductController(appDbContext parmContext)
{
_context = parmContext;
}
now I want to add DAL and in that, getting error creating object of type appDbContext, what to pass/set for parmContext?
below is the connection in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<appDbContext>(config =>
{
config.UseMySql(Configuration.GetConnectionString("PreSales"));
});
}
Below is the code I want to use
public IEnumerable<ProductStatusMaster> GetProductStatusFRdal()
// here I ant to create object of DBcontext (i.e. _context)
{
try
{
var msm = _context.ProductStatusMaster
.Where(s => s.ActiveYn == 1 )
.OrderBy(s => s.Status)
.ToList();
return msm;
}
catch
{
throw;
}
}

Let me get an answer.
There are 2 ways to realize code you want.
1) Through Controller DI.
2) Through Service Locator pattern (antipattern).
By the code:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<appDbContext>(config =>
{
config.UseMySql(Configuration.GetConnectionString("PreSales"));
});
}
you set up dependency for DbContext and configure connection parameters. So, for the first method you should pass the dependency through controller. Possible code will be like this:
public class MyTestAppController
{
private appDbContext _context;
public MyTestApController(appDbContext externalAppDbContext)
{
_context = externalAppDbContext;
}
public IEnumerable<ProductStatusMaster> GetProductStatusFRdal()
{
try
{
var msm = _context.ProductStatusMaster
.Where(s => s.ActiveYn == 1 )
.OrderBy(s => s.Status)
.ToList();
return msm;
}
catch
{
throw;
}
}
}
2) Using Service Locator pattern
In this case you should use IServiceProvider dependency. Code example like this:
public class MyTestAppController
{
private IServiceProvider _provider;
public MyTestAppController(IServiceProvider provider) => _provider = provider;
public IEnumerable<ProductStatusMaster> GetProductStatusFRdal()
{
var _context = _provider.GetService<appDbContext>();
try
{
var msm = _context.ProductStatusMaster .Where(s => s.ActiveYn == 1 )
.OrderBy(s => s.Status) .ToList(); return msm;
}
catch { throw; }
}
}

Related

Unable to resolve service for type 'BusinessServices.CustomerBusinessService' while attempting to activate 'Repository.CustomerRepository'

Issue Message:
System.AggregateException: 'Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: Repository.ICustomerRepository Lifetime: Scoped ImplementationType: Repository.CustomerRepository': Unable to resolve service for type 'BusinessServices.CustomerBusinessService' while attempting to activate 'Repository.CustomerRepository'.)'
API Controller:
namespace WebAPIforAzureSQL.Controllers
{
[Route("api/[controller]")]
[ApiController]
[ApiVersion("1.0")]
[ApiVersion("2.0")]
public class AzureController : ControllerBase
{
private readonly ICustomerRepository customerRepository;
private readonly ICustomerBusinessService customerBusinessService;
public AzureController(ICustomerRepository _customerRepository, ICustomerBusinessService _customerBusinessService)
{
customerRepository = _customerRepository;
customerBusinessService = _customerBusinessService;
}
[MapToApiVersion("1.0")]
[HttpGet]
public IEnumerable<Customers> Customers()
{
return customerRepository.GetAllCustomers();
}
[MapToApiVersion("2.0")]
[HttpGet()]
public Customers OneCustomer([FromHeader] int customerID)
{
return customerRepository.GetCustomer(customerID);
}
[HttpGet()]
[ApiVersion("1.0")]
[ApiVersion("2.0")]
public bool NewCustomer([FromHeader] Customers c)
{
return customerRepository.AddCustomer(c);
}
}
}
Program.cs:
using Microsoft.AspNetCore.Mvc.Versioning;
using Microsoft.AspNetCore.Mvc;
using WebAPIforAzureSQL;
using Microsoft.EntityFrameworkCore;
using Repository;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Contracts;
using BusinessServices;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddControllers().AddXmlSerializerFormatters();
builder.Services.AddSwaggerGen();
builder.Services.ConfigureOptions<ConfigureSwaggerOptions>();
builder.Services.AddApiVersioning(opt =>
{
opt.DefaultApiVersion = new ApiVersion(1, 0);
opt.AssumeDefaultVersionWhenUnspecified = true;
opt.ReportApiVersions = true;
opt.ApiVersionReader = ApiVersionReader.Combine(
new UrlSegmentApiVersionReader(),
new HeaderApiVersionReader("api-version")
);
});
// Add ApiExplorer to discover versions
builder.Services.AddVersionedApiExplorer(setup =>
{
setup.GroupNameFormat = "'v'VVV";
setup.SubstituteApiVersionInUrl = true;
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddDbContext<AmounDB001DbContext>(option =>
{
option.UseSqlServer(builder.Configuration.GetConnectionString("DB001"));
});
//adding Services
builder.Services.AddScoped<ICustomerRepository, CustomerRepository>();
builder.Services.AddScoped<ICustomerBusinessService, CustomerBusinessService>();
var app = builder.Build();
var apiVersionDescriptionProvider =
app.Services.GetRequiredService<IApiVersionDescriptionProvider>();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(
options =>
{
foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions)
{
options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json",
description.GroupName.ToUpperInvariant());
}
}
);
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Repository Class
namespace Repository
{
public class CustomerRepository : ICustomerRepository
{
private readonly AmounDB001DbContext amounDB001DbContext;
private readonly CustomerBusinessService customerBusinessService;
public CustomerRepository(
AmounDB001DbContext _amounDB001DbContext,
CustomerBusinessService _customerBusinessService
)
{
this.amounDB001DbContext = _amounDB001DbContext;
customerBusinessService= _customerBusinessService;
}
public bool AddCustomer(Customers c)
{
if (c != null && customerBusinessService.CheckAllFields(c))
{
amounDB001DbContext.Add(c);
amounDB001DbContext.SaveChangesAsync();
return true;
}
return false;
}
public bool RemoveCustomer(Customers c)
{
if (c != null && customerBusinessService.CheckAllFields(c))
{
amounDB001DbContext.Customers.Remove(c);
amounDB001DbContext.SaveChanges();
return true;
}
return false;
}
public bool UpdateCustomer(Customers c)
{
if (c != null && customerBusinessService.CheckAllFields(c))
{
amounDB001DbContext.Customers.Update(c);
amounDB001DbContext.SaveChanges();
return true;
}
return false;
}
public List<Customers> GetAllCustomers()
{
return amounDB001DbContext.Customers.ToList();
}
public Customers GetCustomer(int customerID)
{
if (customerID == 0)
{
return null;
}
return amounDB001DbContext.Customers.FirstOrDefault(c => c.CustomerID == customerID);
}
}
}
I'm not sure what I'm doing wrong. Any ideas?
I think you should change the constructor of CustomerRepository, replacing the parameter type CustomerBusinessService with the interface you registered as a service ICustomerBusinessService.
public class CustomerRepository : ICustomerRepository
{
private readonly AmounDB001DbContext amounDB001DbContext;
private readonly ICustomerBusinessService customerBusinessService;
public CustomerRepository(
AmounDB001DbContext _amounDB001DbContext,
ICustomerBusinessService _customerBusinessService
)
{
this.amounDB001DbContext = _amounDB001DbContext;
customerBusinessService= _customerBusinessService;
}
...

Impossible to use dependency injection in an Hangfire job

Context
I use Hangfire (version 1.7.11) as a scheduler. But I can't use proper DI in my jobs.
What works so far
I have no problem scheduling something like this, given the fact SomeConcreteService have a parameterless constructor:
RecurringJob.AddOrUpdate<SomeConcreteService>(jobId, mc => Console.WriteLine(
$"Message from job: {mc.GetValue()}"), "1/2 * * * *");
What does not work
But I get an exception when I try to inject a service into a Hangfire job using what is recommended here: https://docs.hangfire.io/en/latest/background-methods/using-ioc-containers.html
When I try to add a new scheduled job using DI, I get the following exception:
Exception thrown: 'System.InvalidOperationException' in System.Linq.Expressions.dll: 'variable 'mc' of type 'TestHangfire.IMyContract' referenced from scope '', but it is not defined'
The exception occurs a this line:
RecurringJob.AddOrUpdate<IMyContract>(jobId, mc => Console.WriteLine(
$"Message from job {jobId} => {mc.GetValue()}"), "1/2 * * * *");
The problem is so trivial that I am sure I am missing something obvious.
Thanks for helping.
The (nearly) full code
Service:
public interface IMyContract
{
string GetValue();
}
public class MyContractImplementation : IMyContract
{
public string _label;
public MyContractImplementation(string label)
{
_label = label;
}
public string GetValue() => $"{_label}:{Guid.NewGuid()}";
}
2 kinds of activators:
public class ContainerJobActivator : JobActivator
{
private IServiceProvider _container;
public ContainerJobActivator(IServiceProvider serviceProvider) =>
_container = serviceProvider;
public override object ActivateJob(Type type) => _container.GetService(type);
}
public class ScopedContainerJobActivator : JobActivator
{
readonly IServiceScopeFactory _serviceScopeFactory;
public ScopedContainerJobActivator(IServiceProvider serviceProvider)
{
_serviceScopeFactory = serviceProvider.GetService<IServiceScopeFactory>();
}
public override JobActivatorScope BeginScope(JobActivatorContext context) =>
new ServiceJobActivatorScope(_serviceScopeFactory.CreateScope());
private class ServiceJobActivatorScope : JobActivatorScope
{
readonly IServiceScope _serviceScope;
public ServiceJobActivatorScope(IServiceScope serviceScope) =>
_serviceScope = serviceScope;
public override object Resolve(Type type) =>
_serviceScope.ServiceProvider.GetService(type);
}
}
Startup:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddHangfire(configuration => configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSqlServerStorage("connection string", new SqlServerStorageOptions
{
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
UseRecommendedIsolationLevel = true,
UsePageLocksOnDequeue = true,
DisableGlobalLocks = true
}));
services.AddHangfireServer();
services.BuildServiceProvider();
services.AddScoped<IMyContract>(i => new MyContractImplementation("blabla"));
// doesn't work either
// services.AddSingleton<IMyContract>(i => new MyContractImplementation("blabla"));
// doesn't work either
// services.AddTransient<IMyContract>(i => new MyContractImplementation("blabla"));
}
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env,
IServiceProvider serviceProvider)
{
// Just to ensure the service is correctly injected...
Console.WriteLine(serviceProvider.GetService<IMyContract>().GetValue());
// I face the problem for both activators: ScopedContainerJobActivator or ContainerJobActivator
GlobalConfiguration.Configuration.UseActivator(new ContainerJobActivator(serviceProvider));
// GlobalConfiguration.Configuration.UseActivator(new ScopedContainerJobActivator(serviceProvider));
app.UseRouting();
app.UseHangfireDashboard();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync(
JsonSerializer.Serialize(
Hangfire.JobStorage.Current.GetConnection().GetRecurringJobs()
.Select(i => new { i.Id, i.CreatedAt, i.Cron }).ToList()));
});
endpoints.MapGet("/add", async context =>
{
var manager = new RecurringJobManager();
var jobId = $"{Guid.NewGuid()}";
// I GET AN EXCEPTION HERE:
// Exception thrown: 'System.InvalidOperationException' in System.Linq.Expressions.dll: 'variable 'mc' of type 'TestHangfire.IMyContract' referenced from scope '', but it is not defined'
manager.AddOrUpdate<IMyContract>(jobId, mc => Console.WriteLine(
$"Message from job {jobId} => {mc.GetValue()}"), "1/2 * * * *");
// doesn't work either: it's normal, it is just a wrapper of what is above
// RecurringJob.AddOrUpdate<IMyContract>(jobId, mc => Console.WriteLine($"Message from job {jobId} => {mc.GetValue()}"), "1/2 * * * *");
await context.Response.WriteAsync($"Schedule added: {jobId}");
});
});
}
}
I found the issue.
As it was actually the expression that seemed to cause an issue, and given the fact that the other way to add a recurring job is to transmit a type, and a method info, it seemed to me that the problem was caused by an expression that was too evolved. So I changed the approach to have a method of my service that make the whole job by being given a parameter.
Here is the new code that works:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Hangfire;
using Hangfire.SqlServer;
using Hangfire.Storage;
using System.Text.Json;
namespace TestHangfire
{
#region Service
public interface IMyContract
{
void MakeAction(string someText);
}
public class MyContractImplementation : IMyContract
{
public string _label;
public MyContractImplementation(string label)
{
_label = label;
}
public void MakeAction(string someText) => Console.WriteLine($"{_label}:{someText}");
}
#endregion
#region 2 kinds of activators
public class ContainerJobActivator : JobActivator
{
private IServiceProvider _container;
public ContainerJobActivator(IServiceProvider serviceProvider)
{
_container = serviceProvider;
}
public override object ActivateJob(Type type)
{
return _container.GetService(type);
}
}
#endregion
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddHangfire(configuration => configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSqlServerStorage("Server=localhost,1433;Database=HangfireTest;user=sa;password=xxxxxx;MultipleActiveResultSets=True", new SqlServerStorageOptions
{
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
UseRecommendedIsolationLevel = true,
UsePageLocksOnDequeue = true,
DisableGlobalLocks = true
}));
services.AddHangfireServer();
services.BuildServiceProvider();
services.AddTransient<IMyContract>(i => new MyContractImplementation("blabla"));
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider)
{
GlobalConfiguration.Configuration.UseActivator(new ContainerJobActivator(serviceProvider));
app.UseRouting();
app.UseHangfireDashboard();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync(JsonSerializer.Serialize(Hangfire.JobStorage.Current.GetConnection().GetRecurringJobs()
.Select(i => new { i.Id, i.CreatedAt, i.Cron }).ToList()));
});
endpoints.MapGet("/add", async context =>
{
var manager = new RecurringJobManager();
var jobId = $"{Guid.NewGuid()}";
manager.AddOrUpdate<IMyContract>(jobId, (IMyContract mc) => mc.MakeAction(jobId), "1/2 * * * *");
await context.Response.WriteAsync($"Schedule added: {jobId}");
});
});
}
}
}

Unable to resolve service for type 'fruittyPie.Models.ShoppingCartItem' while attempting to activate 'fruittyPie.Controllers.CartController'

I'm creating a shopping cart controller first time, I'm stuck in this exception
I know there is a need to add scoped service in startup class, but don't know how to do in my case
InvalidOperationException: Unable to resolve service for type
'fruittyPie.Models.ShoppingCartItem' while attempting to activate
'fruittyPie.Controllers.CartController'.
my startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<AppDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddTransient<IPieRepository, PieRepository>();
services.AddTransient<ICatagoryRepository, CatagoryRepository>();
services.AddTransient<IFeedBackRepository, FeedbackRepository>();
services.AddSingleton<IFileProvider>(
new PhysicalFileProvider(
Path.Combine(
Directory.GetCurrentDirectory(), "wwwroot")
));
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddMvc();
services.AddMemoryCache();
services.AddSession();
}
CartController
public class CartController : Controller
{
//[Route("cart")]
private readonly AppDbContext _appDbContext;
private readonly ShoppingCartItem _shoppingCartItems;
private readonly ShoppingCart _shoppingCart;
public CartController(AppDbContext appDbContext,ShoppingCartItem shoppingCartItem, ShoppingCart shoppingCart)
{
_appDbContext = appDbContext;
_shoppingCartItems = shoppingCartItem;
_shoppingCart = shoppingCart;
}
public string ShoppingCartId { get; set; }
public IActionResult Index()
{
// List<ShoppingCartItem> shoppingCartItems = new List<ShoppingCartItem>();
ViewBag.cart =
_appDbContext.ShoppingCartItemx.Where
(c => c.CartId == ShoppingCartId)
.Include(s => s.productx)
.ToListAsync();
ViewBag.total = _appDbContext.ShoppingCartItemx.Where(d => d.CartId == ShoppingCartId)
.Select(f => f.productx.Price * f.Amount).Sum();
return View();
}
public void AddToCart(Product productz, int amount)
{
var shoppingCartItemz = _appDbContext.ShoppingCartItemx.SingleOrDefault(
s => s.productx.Id == productz.Id && s.CartId == ShoppingCartId);
if (shoppingCartItemz == null)
{
shoppingCartItemz = new ShoppingCartItem
{
CartId = ShoppingCartId,
productx = productz,
Amount = 1
};
_appDbContext.ShoppingCartItemx.Add(shoppingCartItemz);
}
else
{
shoppingCartItemz.Amount++;
}
_appDbContext.SaveChanges();
}
public int RemoveFromCart(Product productz)
{
var shoppingCartItemz = _appDbContext.ShoppingCartItemx.SingleOrDefault(
s => s.productx.Id == productz.Id && s.CartId == ShoppingCartId);
var localAmount = 0;
if (shoppingCartItemz != null)
{
if (shoppingCartItemz.Amount > 1)
{
shoppingCartItemz.Amount--;
localAmount = shoppingCartItemz.Amount;
}
else
{
_appDbContext.ShoppingCartItemx.Remove(shoppingCartItemz);
}
}
_appDbContext.SaveChanges();
return localAmount;
}
}
}
ShoppingCartItem and ShoppingCart are not registered as services but you added them to your constructor. ASP.NET will now try to resolve those parameters from the dependency injection container, which obviously fails.
These parameters do not belong in the constructor. You can remove them and query the desired ShoppingCartItem and/or ShoppinCart entities from the AppDbContext.

Wiring up validation in MediatR and ASP.NET Core using autofac

I've just started to use MediatR in an asp.net core project and am struggling to wire up validation ...
Here's my controller:
public class PersonController : Controller
{
IMediator mediator;
public PersonController(IMediator mediator)
{
this.mediator = mediator;
}
[HttpPost]
public async Task<ActionResult> Post([FromBody]CreatePerson model)
{
var success = await mediator.Send(model);
if (success)
{
return Ok();
}
else
{
return BadRequest();
}
}
}
... and the CreatePerson command, validation (via FluentValidation) and request handler:
public class CreatePerson : IRequest<bool>
{
public string Title { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
}
public class CreatePersonValidator : AbstractValidator<CreatePerson>
{
public CreatePersonValidator()
{
RuleFor(m => m.FirstName).NotEmpty().Length(1, 50);
RuleFor(m => m.Surname).NotEmpty().Length(3, 50);
}
}
public class CreatePersonHandler : IRequestHandler<CreatePerson, bool>
{
public CreatePersonHandler()
{
}
public bool Handle(CreatePerson message)
{
// do some stuff
return true;
}
}
I have this generic validation handler:
public class ValidatorHandler<TRequest, TResponse> : IRequestHandler<TRequest, TResponse> where TRequest : IRequest<TResponse>
{
private readonly IRequestHandler<TRequest, TResponse> inner;
private readonly IValidator<TRequest>[] validators;
public ValidatorHandler(IRequestHandler<TRequest, TResponse> inner, IValidator<TRequest>[] validators)
{
this.inner = inner;
this.validators = validators;
}
public TResponse Handle(TRequest message)
{
var context = new ValidationContext(message);
var failures = validators
.Select(v => v.Validate(context))
.SelectMany(result => result.Errors)
.Where(f => f != null)
.ToList();
if (failures.Any())
throw new ValidationException(failures);
return inner.Handle(message);
}
}
... but I'm struggling to wire the validation up correctly in Startup.ConfigureServices using autofac:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
var builder = new ContainerBuilder();
builder.Register<SingleInstanceFactory>(ctx =>
{
var c = ctx.Resolve<IComponentContext>();
return t => c.Resolve(t);
});
builder.Register<MultiInstanceFactory>(ctx =>
{
var c = ctx.Resolve<IComponentContext>();
return t => (IEnumerable<object>)c.Resolve(typeof(IEnumerable<>).MakeGenericType(t));
});
builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof(CreatePersonHandler).GetTypeInfo().Assembly).AsClosedTypesOf(typeof(IRequestHandler<,>));
builder.RegisterGenericDecorator(typeof(ValidatorHandler<,>), typeof(IRequestHandler<,>), "Validator").InstancePerLifetimeScope();
builder.Populate(services);
var container = builder.Build();
return container.Resolve<IServiceProvider>();
}
When I run the app and POST /api/person
{
"title": "Mr",
"firstName": "Paul",
"surname": ""
}
I get a 200.
CreatePersonHandler.Handle() was called but CreatePersonValidator() is never called.
Am i missing something in Startup.ConfigureServices()?
I suggest that you read the official documentation on how to wire up decorators in Autofac.
Decorators use named services to resolve the decorated services.
For example, in your piece of code:
builder.RegisterGenericDecorator(
typeof(ValidatorHandler<,>),
typeof(IRequestHandler<,>),
"Validator").InstancePerLifetimeScope();
you're instructing Autofac to use ValidationHandler<,> as a decorator to IRequestHandler<,> services that have been registered with the Validator name, which is probably not what you want.
Here's how you could get it working:
// Register the request handlers as named services
builder
.RegisterAssemblyTypes(typeof(CreatePersonHandler).GetTypeInfo().Assembly)
.AsClosedTypesOf(typeof(IRequestHandler<,>))
.Named("BaseImplementation");
// Register the decorators on top of your request handlers
builder.RegisterGenericDecorator(
typeof(ValidatorHandler<,>),
typeof(IRequestHandler<,>),
fromKey: "BaseImplementation").InstancePerLifetimeScope();
I find specifying the name of the fromKey parameter helps in understanding how decorators work with Autofac.

SetterProperty injection using structuremap to Asp.Net MVC ActionFilter

Why I am not able to inject the SetterProperty via StructureMap to an MVC ActionFilter?
public class LockProjectFilter : ActionFilterAttribute
{
[SetterProperty]
public ISecurityService SecurityService { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var loggedinStaffId = SecurityService.GetLoggedInStaffId();
if (loggedinStaffId == 1)
throw new ArgumentNullException();
base.OnActionExecuting(filterContext);
}
}
public static IContainer Initialize()
{
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.AssemblyContainingType<ISecurityService>();
});
x.SetAllProperties(p => p.OfType<ISecurityService>());
//x.ForConcreteType<LockProjectFilter>().Configure
// .Setter(c => c.SecurityService).IsTheDefault();
});
return ObjectFactory.Container;
}
You need to utilize the 'BuildUp' method off the ObjectFactory.
http://docs.structuremap.net/ConstructorAndSetterInjection.htm#section4
[Test]
public void create_a_setter_rule_and_see_it_applied_in_BuildUp_through_ObjectFactory()
{
var theGateway = new DefaultGateway();
ObjectFactory.Initialize(x =>
{
x.ForRequestedType<IGateway>().TheDefault.IsThis(theGateway);
// First we create a new Setter Injection Policy that
// forces StructureMap to inject all public properties
// where the PropertyType is IGateway
x.SetAllProperties(y =>
{
y.OfType<IGateway>();
});
});
// Create an instance of BuildUpTarget1
var target = new BuildUpTarget1();
// Now, call BuildUp() on target, and
// we should see the Gateway property assigned
ObjectFactory.BuildUp(target);
target.Gateway.ShouldBeTheSameAs(theGateway);
}
Then you can create a new FilterAttributeFilterProvider like this:
public class DependencyResolverFilterProvider : FilterAttributeFilterProvider
{
public override IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
var filters = base.GetFilters(controllerContext, actionDescriptor);
foreach (var filter in filters)
{
//DI via Setter Injection
DependencyResolver.BuildUp(filter.Instance);
}
return filters;
}
}
Then finally add your custom filter provider to the .net pipeline.
private static void RegisterProviderAndFilters()
{
var oldProvider = FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider);
FilterProviders.Providers.Remove(oldProvider);
FilterProviders.Providers.Add(new DependencyResolverFilterProvider());
RegisterGlobalFilters(GlobalFilters.Filters);
}
Hope this helps!
wm