0

I have an instance where my controller is never instantiated when i use Autofac. I figured I have done something wrong with the configuration, but I cannot figure it out. I have 2 projects within my solution. 1) API 2) Core All the models, repository, and services live in the Core. Only the controllers are in the API.

If I navigate to the default or values controller, they work fine. If I remove the constructor from my MemberController, it will work, but I get NULL references on the service. If I add the constructor back, the MemberController never loads (break point in constructor and get method) are never hit.

The Service requires a data model on instantiation. In the instance below, the MemberController takes a MemberService<MemberDM> as an IService<IDataModel>. I believe I have registered everything within my AutofacModule, but it doesn't seem to be working, as the constructor is never hit in MemberController.

Any thoughts/help would be much appreciated.

Startup.cs

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();
        Configuration = builder.Build();
    }

    public IContainer ApplicationContainer { get; private set; }
    public IConfigurationRoot Configuration { get; private set; }


    // This method gets called by the runtime. Use this method to add services to the container.
    public IServiceProvider ConfigureServices(IServiceCollection services)
    {

        // Add service and create Policy with options
        services.AddCors(o => o.AddPolicy("CorsPolicy", p =>
        {
            p.AllowAnyOrigin()
             .AllowAnyMethod()
             .AllowAnyHeader()
             .AllowCredentials();
        }));    

        // Add framework services.
        services.AddMvc();

        var builder = new ContainerBuilder();
        var connectionString = Configuration.GetValue<string>("DBConnection:ConnectionString");

        builder.RegisterModule(new AutofacModule(connectionString));

        builder.Populate(services);
        ApplicationContainer = builder.Build();
        return new AutofacServiceProvider(ApplicationContainer);

    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationLifetime appLifetime)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();
        app.UseCors("CorsPolicy");
        app.UseMvc();

        appLifetime.ApplicationStopped.Register(() => this.ApplicationContainer.Dispose());
    }
}

AutofacModule

public class AutofacModule :Autofac.Module
{
    private string _connectionString;

    public AutofacModule(string connectionString)
    {
        _connectionString = connectionString;
    }

    protected override void Load(ContainerBuilder builder)
    {            
        // Register Connection class and expose IConnection 
        // by passing in the Database connection information
        builder.RegisterType<Connection>() // concrete type
            .As<IConnection>() // abstraction
            .WithParameter("connectionString", _connectionString)
            .InstancePerLifetimeScope();

        // Register Repository class and expose IRepository
        builder.RegisterType<Repository>() // concrete type
            .As<IRepository>() // abstraction
            .InstancePerLifetimeScope();

        // Register DataModel as IDataModel 
        builder.RegisterAssemblyTypes(typeof(IServiceAssembly).GetTypeInfo().Assembly)
            .Where(t => t.Name.EndsWith("DM"))
            //.AsImplementedInterfaces();
            .As<IDataModel>();

        // Register Service Class as IService
        builder.RegisterAssemblyTypes(typeof(IServiceAssembly).GetTypeInfo().Assembly)
            .Where(t => t.Name.EndsWith("Service"))
            .Except<IService<IDataModel>>()
            //.AsImplementedInterfaces();
            .As<IService<IDataModel>>();
    }
}

IServiceAssembly

 public interface IServiceAssembly
{
}

MemberController

 [Route("api/[controller]")]
public class MemberController : Controller
{

    private readonly IService<MemberDM> _memberService;

    public MemberController(IService<MemberDM> service)
    {
        _memberService = service;
    }

    // GET: api/values
    [HttpGet]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

    // GET api/values/5
    [HttpGet("{id}")]
    public async Task<IActionResult> Get(int id)
    {
        var result = await _memberService.Get(id);
        return View(result);
    }}
3
  • Wouldn't it be because of .Except<IService<IDataModel>>() call? If your MemberDM implements IDataModel interface then it wouldn't be registered as far as I see it Commented May 14, 2017 at 9:22
  • I tried removing that, and it still doesn't work. Commented May 14, 2017 at 14:31
  • Are your services generics? .Name for generics returns TypeName`n, where n is number of generic parameters. i.e. MyService<MemberDM> will return MyService`1 as Name, not MyService Commented May 14, 2017 at 16:53

1 Answer 1

2

Assuming following:

  • IService<T> and IDataModel implements IServiceAssembly.
  • All interfaces ending with "DM" or "Service" in your Core project have corresponding implementations.

Then it's enough to have a single DI registration statement in your API project.

// Register DataModel as IDataModel 
// Register Service Class as IService
builder.RegisterAssemblyTypes(typeof(IServiceAssembly).GetTypeInfo().Assembly)
    .Where(t => t.Name.EndsWith("DM") || t.Name.EndsWith("Service"))
    .AsImplementedInterfaces();
Sign up to request clarification or add additional context in comments.

1 Comment

Thanx for this. I like how you combined them. I think the issue was me trying to use the actual Interface instead of using .AsImplementedInterfaces().

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.