AspNet Core and Autofac Dependency Resolution Exception - asp.net-core

I'm trying to use Autofac in a multi-tenant application and I need to inject DefaultIdentity as following:
c.Register(c =>
{
var opt = new DbContextOptionsBuilder<ApplicationDbContext>();
opt.UseSqlServer(scm.GetConnectionString("ReservedArea_" + t.DatabaseSuffix));
return new ApplicationDbContext(opt.Options);
}).AsSelf()
.InstancePerLifetimeScope();
....
tenantServices.AddDefaultIdentity<ApplicationUser>(options =>
{
options.SignIn.RequireConfirmedAccount = true;
options.User.RequireUniqueEmail = false;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddSignInManager<AppSignInManager<ApplicationUser>>()
.AddUserManager<AppUserManager<ApplicationUser>>();
c.Populate(tenantServices);
Where "c" is my containerBuilder and tenantServices my list of services to inject.
When I authenticate all works fine but after that, when application redirects to another page, I receive following error:
DependencyResolutionException: None of the constructors found with
'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type
'RA.WEB.Classes.Account.AppSignInManager1[RA.WEB.Data.ApplicationUser]' can be invoked with the available services and parameters: Cannot resolve parameter 'RA.WEB.Data.ApplicationDbContext dbContext' of constructor 'Void .ctor(Microsoft.AspNetCore.Identity.UserManager1[RA.WEB.Data.ApplicationUser],
Microsoft.AspNetCore.Http.IHttpContextAccessor,
Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactory1[RA.WEB.Data.ApplicationUser], Microsoft.Extensions.Options.IOptions1[Microsoft.AspNetCore.Identity.IdentityOptions],
Microsoft.Extensions.Logging.ILogger1[Microsoft.AspNetCore.Identity.SignInManager1[RA.WEB.Data.ApplicationUser]],
RA.WEB.Data.ApplicationDbContext,
Microsoft.AspNetCore.Authentication.IAuthenticationSchemeProvider,
Microsoft.AspNetCore.Identity.IUserConfirmation`1[RA.WEB.Data.ApplicationUser])'.
Autofac.Core.Activators.Reflection.ReflectionActivator.GetAllBindings(ConstructorBinder[]
availableConstructors, IComponentContext context,
IEnumerable parameters)
DependencyResolutionException: An exception was thrown while
activating
Microsoft.AspNetCore.Identity.SecurityStampValidator1[[RA.WEB.Data.ApplicationUser, RA.WEB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] -> RA.WEB.Classes.Account.AppSignInManager1[[RA.WEB.Data.ApplicationUser,
RA.WEB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].
What am I doing wrong?
Thanks in advance for your help

Related

Cannot create database migration on EF Core but It can when you ask to EnsureCreate database

I am trying to inject some repository to a service and some services to a controller but I am using the DbContext is an assembly that is not the startup project but oddily when i try to call to create a migration it tells me this design is not allowed but if I call the EnsureCreated() method it allows me to create the database... what could be happening
the error
Microsoft.EntityFrameworkCore.Design.OperationException: Unable to create an object of type 'AppDbContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
---> System.InvalidOperationException: Unable to resolve service for type 'Microsoft.EntityFrameworkCore.DbContextOptions1[Repository.AppDbContext.AppDbContext]' while attempting to activate 'Repository.AppDbContext.AppDbContext'. at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider) at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters) at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetServiceOrCreateInstance(IServiceProvider provider, Type type) at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.<>c__DisplayClass13_4.<FindContextTypes>b__13() --- End of inner exception stack trace --- at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.<>c__DisplayClass13_4.<FindContextTypes>b__13() at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func1 factory)
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl
here is the Service DI
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContextPool<AppDbContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("ManagementServiceDb"));
});
services.AddIdentity<ApplicationUser, IdentityRole>(options => {
options.SignIn.RequireConfirmedAccount = false;
options.User.RequireUniqueEmail = true;
}).AddEntityFrameworkStores<AppDbContext>();
services.AddScoped<IRepository<Producto>, ProductoRepositorio>();
services.AddScoped<IRepository<RegistroActividad>, RegistroActividadRepositorio>();
services.AddScoped<IRepository<ProductoRegistroActividad>, RegistroActividadesProductoRepositorio>();
services.AddScoped<IRepository<TipoActividad>, TipoActividadRepositorio>();
services.AddScoped<IRepository<ApplicationUser>, UsuarioRepositorio>();
services.AddScoped<UnidadRepositorio>();
services.AddScoped<ProductosServicios>();
services.AddScoped<UsuarioServicio>();
services.AddScoped<UnidadServicios>();
services.AddControllersWithViews();
}
Try to add a parameterless constructor in your DbContext class.
If that doesn't work you might need to add a design time factory as described here.

TypeLoadException in ASP.NET DevExtreme Datagrid when specifying columns

I'm customizing the columns I need for a datagrid in DevExtreme. Below is my Index.cshtml and my action method to load the data. The model has more attributes but I only want to include these three.
#(Html.DevExtreme().DataGrid<ServicingRequestOrder.Models.GeneralInfo>
()
.ID("dataGrid")
.ShowBorders(true)
.DataSource(d => d.Mvc().Controller("GeneralInfo").LoadAction("IndexLoad").Key("ID"))
.Columns(columns =>
{
columns.AddFor(m => m.CustomerID);
columns.AddFor(m => m.Name);
columns.AddFor(m => m.Description);
}).
[HttpGet]
public object IndexLoad(DataSourceLoadOptions loadOptions)
{
var generalInfos = _context.GeneralInfos.ToList();
return DataSourceLoader.Load(generalInfos, loadOptions);
}
The specific exception I'm getting is
TypeLoadException: Could not load type 'Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ExpressionHelper' from assembly 'Microsoft.AspNetCore.Mvc.ViewFeatures, Version=3.1.7.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'.
I have included this service in my Startup.cs as well.
services.AddMvc().AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
What am I missing here.
TypeLoadException: Could not load type 'Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ExpressionHelper' from assembly 'Microsoft.AspNetCore.Mvc.ViewFeatures, Version=3.1.7.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'.
In ASP.NET Core 3.0, some pubinternal APIs (includes Microsoft.AspNetCore.Mvc.ViewFeatures.Internal namespace) are updated to be truly internal, which seems cause this issue.
For more information about "Making "pubinternal" types in MVC internal", please check this link: https://github.com/dotnet/aspnetcore/issues/4932 .
As a possible workaround, you can try to setup the project with ASP.NET Core 2.x rather than ASP.NET Core 3+ version.
The issue is resolved. By default when I installed Devextreme in the dependencies, it wasn't the latest version. After some checking, I had to update the version of Devextreme and it's all good now.

Autofac and Automapper - Profiles registred but not resolved

I have a ASP.NET Core app that uses Autofac to inject Automapper.
Firstly, I'm trying to register Automapper profiles from Assembly:
builder.RegisterAssemblyTypes(assembly)
.AssignableTo<Profile>()
.OnActivated(e => System.Diagnostics.Debug.WriteLine(e.Instance.GetType()))
.AutoActivate();
I have introduced some debug logs to check whether my profiles are registred. And it works, I see my profiles in debug window.
Than I register Automapper and try to resolve previously registered profiles:
builder.Register(ctx => new MapperConfiguration(cfg =>
{
var resolvedProfiles = ctx.Resolve<IEnumerable<Profile>>(); // Length is 0
foreach(var resolvedProfile in resolvedProfiles)
{
cfg.AddProfile(resolvedProfile);
}
}).CreateMapper())
.SingleInstance();
Doesn't work unfortunantely. Autofac doesn't resolve any of the previously registered profiles. Why and how can I fix it?
Just add the type to your registration (via .As<Profile>()):
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.AssignableTo<Profile>()
.As<Profile>()
.OnActivated(e => System.Diagnostics.Debug.WriteLine(e.Instance.GetType()))
.AutoActivate();

Assembly.LoadFrom(assemblypath) in WCF Servicefactory

I am using a WCF ServicehostFactory for my wcf service in conjunction with unity for service and repository/DAL instantiation using interfaces.
I want to load an assembly into my appdomain (before the service is instantiated), whose types are registered in my web.config for Unity DI.
<assembly name="Customer.DAL.AdventureWorks"/>
<assembly name="Customer.DAL.Blogger"/>
<assembly name="Customer.Interfaces"/>
<assembly name="Customer.DAL"/>
<namespace name="Customer.Interfaces.Repository"/>
<namespace name="Customer.DAL.AdventureWorks"/>
<namespace name="Customer.DAL.Blogger"/>
<container>
<register type="Customer.Interfaces.DAL.IDal, Customer.Interfaces" mapTo="Customer.DAL.API, Customer.DAL">
<lifetime type="transient"/>
</register>
<register type="Customer.Interfaces.Repository.IRepositoryDepartment, Customer.Interfaces" mapTo="Customer.DAL.AdventureWorks.RepositoryDepartment, Customer.DAL.AdventureWorks">
<lifetime type="transient"/>
</register>
<register type="Customer.Interfaces.Repository.IRepositoryBlogs, Customer.Interfaces" mapTo="Customer.DAL.Blogger.RepositoryBlogs, Customer.DAL.Blogger">
<lifetime type="transient"/>
</register>
</container>
and I am using the following code to load the assembly:
Assembly.LoadFile("C:\xxxxx\Customer.DAL.dll"); // loaded from somewhere on disk.
I have verified the existence of the loaded assembly against the current appdomain and the assembly is loaded successfully.
Immediately after that, I try to register the service type using unity, but I get the following exception:
The type name or alias Customer.DAL.API, Customer.DAL could not be resolved. Please check your configuration file and verify this type name.
So why can the type "Customer.DAL.API" not be resolved?
EDIT: I run FusionLog in parallel and it traces out the failed assembly binding.
Why does it actually search for the assembly, cause the this assembly has already been loaded by me using reflection as mentioned above?!
EDIT-II:
#Tuzo:
I read all the articles you posted.
And tried the following:
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
AssemblyName asname = AssemblyName.GetAssemblyName(#"C:\xxxx\KM_Solution\Customer.DAL\bin\Debug\Customer.DAL.dll");
return Assembly.Load(asname);
}
But I still get the exception. I checked AppDomain.CurrentDomain.GetAssemblies() and I can find my assembly, but it still throws the exception that Unity cannot resolve the type...
I would handle the AssemblyResolve event and load the assembly if you need to:
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
IUnityContainer container = new UnityContainer()
.LoadConfiguration();
// Example of resolving without hard reference
var customerDal = container.Resolve(
Type.GetType("Customer.Interfaces.Repository.IRepositoryDepartment, Customer.Interfaces"));
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string assemblyName = #"C:\xxxxx\" + args.Name + ".dll";
if (File.Exists(assemblyName))
{
return Assembly.LoadFile(assemblyName);
}
return null;
}
In terms of why LoadFile doesn't work, the reason is the Load Context. There are 3 contexts: Load, LoadFrom, and Neither. When you use LoadFile or Load(byte[]) then the assembly is loaded into the Neither context. In the neither context nothing can bind to the assembly without using AssemblyResolve.
See:
Understanding The CLR Binder
Best Practices for Assembly Loading
Suzanne Cook's Blog: Choosing a Binding Context and LoadFile vs. LoadFrom

How to add WCF custom binding element extensions client-side in code, without any config files?

Situation
I have a client library that uses the Windows Azure AppFabric Service Bus NetTcpRelayBinding to connect to the endpoint. The client library is hosted by an application, that is not necessarily a .NET-application. Anyway, app.config is out of the question, which means everything should be configured in code.
Machine.config is one option, but it's better if it can be avoided. A local custom proxy or a front-end server could be another option, but I'd like to explore this option first, before changing architecture that radically.
There are no problems with system bindings, but I haven't figured out or found a solution how to add the following configuration to a ChannelFactory in code:
<extensions>
<bindingElementExtensions>
<add name="tcpRelayTransport" type="Microsoft.ServiceBus.Configuration.TcpRelayTransportElement, Microsoft.ServiceBus, Version=1.6.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</bindingElementExtensions>
<bindingExtensions>
<add name="netTcpRelayBinding" type="Microsoft.ServiceBus.Configuration.NetTcpRelayBindingCollectionElement, Microsoft.ServiceBus, Version=1.6.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</bindingExtensions>
</extensions>
Here is the solution that has now been tested. Hopefully it makes clear, what the problem really was and maybe it helps somebody else with a similar problem. Credits to co-worker, who had the time to investigate the issue.
The solution was to edit dynamically the configuration and add the reference to the required Binding Element Extensions (without app.config in any layer or without changing machine.config in client machines):
var service = ServiceModelSectionGroup.GetSectionGroup(ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None));
var tcpRelayTransportExtension = new ExtensionElement("tcpRelayTransport", "Microsoft.ServiceBus.Configuration.TcpRelayTransportElement, Microsoft.ServiceBus, Version=1.6.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
var netTcpRelayTransportExtension = new ExtensionElement("netTcpRelayBinding", "Microsoft.ServiceBus.Configuration.NetTcpRelayBindingCollectionElement, Microsoft.ServiceBus, Version=1.6.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
if (service.Extensions.BindingElementExtensions.ContainsKey(tcpRelayTransportExtension.Name) == false)
{
service.Extensions.BindingElementExtensions.Add(tcpRelayTransportExtension);
}
if (service.Extensions.BindingElementExtensions.ContainsKey(netTcpRelayTransportExtension.Name) == false)
{
service.Extensions.BindingElementExtensions.Add(netTcpRelayTransportExtension);
}
Thanks to everyone who tried to help, though!
You can add the binding element extension via code by writing a custom service host factory. A similar question has been answered here
Based on your type of WCF service you just need to inherit the appropriate servicehostfactory class when writing a custom service host factory. For example as shown below:
How to build a custom service host
If building a REST WCF Service use WebServiceHostFactory
If building a WCF service use ServiceHostFactory
A sample for this without config is available here: http://code.msdn.microsoft.com/windowsazure/Relayed-Messaging-Windows-0d2cede3
Following is the code snippet:
ChannelFactory<IEchoChannel> channelFactory = null;
IEchoChannel channel = null;
try
{
//Create a Behavior for the Credentials
TransportClientEndpointBehavior sharedSecretServiceBusCredential = new TransportClientEndpointBehavior();
sharedSecretServiceBusCredential.TokenProvider = TokenProvider.CreateSharedSecretTokenProvider(issuerName, issuerSecret);
//Create a Channel Factory
channelFactory = new ChannelFactory<IEchoChannel>(new NetTcpRelayBinding(), new EndpointAddress(serviceAddress));
channelFactory.Endpoint.Behaviors.Add(sharedSecretServiceBusCredential);
LogMessage("Opening channel to: {0}", serviceAddress);
channel = channelFactory.CreateChannel();
channel.Open();
LogMessage("Sending: {0}", echoTextBox.Text);
string echoedText = channel.Echo(echoTextBox.Text);
LogMessage("Received: {0}", echoedText);
echoTextBox.Text = string.Empty;
LogMessage("Closing channel");
channel.Close();
LogMessage("Closing factory");
channelFactory.Close();
}
catch (Exception ex)
{
LogMessage("Error sending: {0}<br/>{1}", ex.Message, ex.StackTrace.Replace("\n", "<br/>"));
// Close the channel and factory properly
if (channel != null)
{
CloseCommunicationObject(channel);
}
if (channelFactory != null)
{
CloseCommunicationObject(channelFactory);
}
}