SimpleInjector MvcSitemapProvider - c#

I'm using
VS2013 MVC5,
SimpleInjector 2.4.1
MvcSiteMapProvider.MVC5.DI.SimpleInjector.Modules 4.4.10
and I'm getting the following error when calling 'Verify' on the container
Additional information: The configuration is invalid. Creating the instance for type IAttributeAssemblyProvider failed. The registered delegate for type IAttributeAssemblyProvider threw an exception. The constructor of the type AttributeAssemblyProvider contains the parameter of type IEnumerable<String> with name 'includeAssemblies' that is not registered. Please ensure IEnumerable<String> is registered in the container, or change the constructor of AttributeAssemblyProvider.
The array it is referencing is :
string[] includeAssembliesForScan = new string[] { "MyProject" };
and this is what seems to be the culprit :
container.RegisterSingle<ReflectionSiteMapNodeProvider>(() =>
container.GetInstance<ReflectionSiteMapNodeProviderFactory>()
.Create(includeAssembliesForScan));
The signature for the create method is :
public MvcSiteMapProvider.Builder.ReflectionSiteMapNodeProvider Create(System.Collections.Generic.IEnumerable<string> includeAssemblies)
Member of MvcSiteMapProvider.Builder.ReflectionSiteMapNodeProviderFactory
I think the IAttributeAssemblyProvider is being registered as per below
// Single implementations of interface with matching name (minus the "I").
CommonConventions.RegisterDefaultConventions(
(interfaceType, implementationType) => container.RegisterSingle(interfaceType, implementationType),
new Assembly[] { siteMapProviderAssembly },
allAssemblies,
excludeTypes,
string.Empty);
since :
public class AttributeAssemblyProvider : IAttributeAssemblyProvider
and the ctor is :
public AttributeAssemblyProvider(
IEnumerable<string> includeAssemblies,
IEnumerable<string> excludeAssemblies)
{...}
Thanks in advance for any help
stack trace is :
at SimpleInjector.InstanceProducer.VerifyExpressionBuilding() at
SimpleInjector.Container.VerifyIfAllExpressionsCanBeBuilt(InstanceProducer[]
producersToVerify) at
SimpleInjector.Container.VerifyIfAllExpressionsCanBeBuilt() at
SimpleInjector.Container.Verify() at
MyProject.App_Start.SimpleInjectorInitializer.Intialise() in
\App_Start\SimpleInjectorInitializer.cs:line 54 at
MyProject.MvcApplication.Application_Start() in \Global.asax.cs:line
16

The latest versions of the external DI config files don't automatically update when you upgrade if you have changed them. Be sure you have merged in the latest versions of CommonConventions.cs and MvcSiteMapProviderContainerInitializer.cs from the master branch (this is to be done manually, but it helps a lot if you use a diff tool to quickly see the changes). You can also view the releases list to see the various points where updates were done to the DI configuration with direct links to the diff on GitHub.
The latest version of CommonConventions.RegisterDefaultConventions excludes auto-registration of any types that have a string parameter in the constructor (which AttributeAssemblyProvider does), so be sure you have merged the latest changes of that file into your project.
Of course, if all else fails you can add typeof(AttributeAssemblyProvider) to the excludeTypes array and it will no longer be auto-registered. It is not supposed to be because it has a factory class that instantiates it named AttributeAssemblyProviderFactory.
Also, if you are not using MvcSiteMapNodeAttribute to register nodes, it is not necessary to have it in your configuration at all. Removing it will make your SiteMap load a little faster.
To remove it, change this...
container.RegisterSingle<ReflectionSiteMapNodeProvider>(() => container.GetInstance<ReflectionSiteMapNodeProviderFactory>()
.Create(includeAssembliesForScan));
// Register the sitemap builders
container.RegisterSingle<ISiteMapBuilder>(() => container.GetInstance<SiteMapBuilderFactory>()
.Create(new CompositeSiteMapNodeProvider(container.GetInstance<XmlSiteMapNodeProvider>(), container.GetInstance<ReflectionSiteMapNodeProvider>())));
To this...
// Register the sitemap builders
container.RegisterSingle<ISiteMapBuilder>(() => container.GetInstance<SiteMapBuilderFactory>()
.Create(container.GetInstance<XmlSiteMapNodeProvider>()));
This is exactly what the "MvcSiteMapProvider_ScanAssembliesForSiteMapNodes" web.config setting does when set to "false" when you are using the internal DI container.

Related

Switch Dll Reference to different version at runtime

In my .NET Application (.NET Framework 4.8) I am trying to implement an exchange of the implementation of one of my interfaces.
I have got the following project structure:
MyProgram.Exchange:
public interface IExchange {
void DoSomething();
}
MyProgram.Exchange.V1 (Reference to Some.dll (Version 1.0.0.0))
[Export(typeof(IExchange))]
public class Exchange : IExchange {
public void DoSomething(){}
}
MyProgram.Exchange.V2 (Reference to Some.dll (Version 2.0.0.0))
[Export(typeof(IExchange))]
public class Exchange : IExchange {
public void DoSomething(){}
}
In my Startup.cs of my main program I create a DirectoryCatalog and register the Types inside my V1 as default behaviour:
var catalog = new DirectoryCatalog($".", $"*V1*.dll");
// ...
var builder = new Autofac.ContainerBuilder();
builder.RegisterComposablePartCatalog(catalog);
Initially this works fine. But at some point further inside my Application I need to switch the Reference from V1 to V2.
My Problem now is, that when calling "builder.RegisterComposablePartCatalog(catalog)" I get an exception, because the referenced assembly "Some.dll" is already registered with another version.
Is there a way to completely remove the reference to MyProgram.Exchange.V1 and all its dependencies and register the MyProgram.Exchange.V2 instead.
Sorry if the explanation of the problem isnt the best, but I hope you get my problem.
I think in the case the option is to load assemblies dynamically using custom AppDomain.
You can realize it like:
create AppDomainAppDomain.CreateDomain()
Assembly.Load()
use instance / register your types using reflection
And when you'll need to replace the dll:
remove the types from DI registration
remove the AppDomain AppDomain.Unload() (the way to UNLOAD already loaded assemblies)
load new assemlby and register types using reflection analogically.
Unfortunately, when you reference dll at compile time, there's no option to "unload" it.

no parameterless constructor defined for type dbcontext

I search many posts in stack and another sites about this error but it wasn't my answer
this is my DbCintext
[Table("AspNetUsers")]
public class ApplicationUser : IdentityUser { }
public class EMSContext : IdentityDbContext<ApplicationUser> {
public EMSContext (DbContextOptions<EMSContext> options) : base (options) { }
public DbSet<Ambulance> Ambulances { get; set; }
}
and this is mu StartUp.cs
services.AddControllers();
services.AddDbContext<EMSContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
but when I want to generate api controller I got this error
no parameterless constructor defined for type dbcontext
The error is clear, you don't have a parameterless constructor.
But that said, the tooling shouldn't need it since you are calling AddDbContext and passing in your connection string. The tooling scaffolds controllers/etc. by actually running your program and then requesting the DbContext from the host's service provider. It does this by looking for methods with very specific names.
My guess is that your main Program.cs is not following the prescribed upon pattern and thus cannot construct your Host nor locate its ServiceProvider.
Your options are as follows (my personal choice is #2):
Add a paremeterless constructor like the message says
Make sure your main entry point uses the correct conventions for the host builder methods
Create a Design-Time context factory
Parameterless Constructor
This is the obvious answer, though it's not always possible. Furthermore it should not be necessary since the scaffolding has other means by which to read from your DbContext. Adding a constructor just for this purpose is not something I would do nor recommend.
Correct Naming / Method Signature
The scaffolding looks for a very specific method signature when it attempts to run your program. Basically, it is looking for something like this:
public class Program
{
public static void Main(string[] args)
=> CreateHostBuilder(args).Build().Run();
// EF Core uses this method at design time to access the DbContext
public static IHostBuilder CreateHostBuilder(string[] args)
=> Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(
webBuilder => webBuilder.UseStartup<Startup>());
}
Now it doesn't need to look exactly like this. The important part is the name and signature of the CreateHostBuilder method.*
If there are any errors raised while attempting to construct the service, for example because there are dependencies that cannot be resolved or configuration is missing then this method will fail. I'm pretty sure you will get either the same error or a DI-related one.**
Design Time Factory
Supposing that still doesn't work or you'd like better control you can create a Design-Time Factory for your context. The tooling will scan your project for types implementing IDesignTimeDbContextFactory<EMSContext> and then use that during scaffolding:
public class EMSContextFactory : IDesignTimeDbContextFactory<EMSContext>
{
public EMSContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<EMSContext>();
optionsBuilder.UseSqlServer("Your Connection String");
return new EMSContext(optionsBuilder.Options);
}
}
See this link for more information.
* Note: You've not specified what version of aspnet core you are running. If you aren't using the generic host (Host.CreateDefaultBuilder) but are instead using WebHost, then the expected method signature will look a bit different. That said it will match that of creating a new project with the same settings.
If you've ever written integration tests for your controllers, the WebApplicationFactory looks for similar methods/signatures. Those same signatures should satisfy the controller scaffolding. I can't seem to find documentation on either other than the link above.
** When the scaffolding runs, it executes as the 'Production' environment. DI errors can occur if service resolution/configuration fails due to being in the "wrong" environment. This is one of the reasons the context factory solution exists.
The error is exactly located in this line:
public EMSContext (DbContextOptions<EMSContext> options) : base (options) { }
No parameterless constructors for DbContext... of course, because your constructor takes one parameter DbContextOptions options,
so you have two options to fix it, fix the call to the constructor or make the constructor take 0 parameters
Here's the error I was getting, sounds very similar to yours.
I had encountered this problem when trying to create a View (the one circled in red). My issue was the Startup.cs file. I had recently done a re-name from LeaveHistory... to LeaveRequest..., and when editing my Startup.cs file I made an incorrect change.
Line 39 should read:
services.AddScoped<ILeaveRequestRepository, LeaveRequestRepository>(); // no "I"
The error I was getting mentioned that the dbContext class didn't have a parameterless constructor - so it was totally deceptive, or at least not that helpful.
So to anyone else looking at this error, don't take it on it's face! I am fairly deep into this project, and none of my other controllers have parameterless constructors, at least not written out.
Think about other clerical changes you've made - class name changes, things like that. Perhaps the error message is not actually what it seems, and you've made a small error somewhere else that is simply generating a confusing error message.

Missing Dependency Injection Register? Cannot resolve parameter X

I am a little lost as to where I need to look to resolve the error message below.
The history is that I added a new service object to the project and instantiate / inject it when a new section of the site is accessed. (MVC 3 site repository/service architecture).
The error is:
Cannot resolve parameter 'XService pl_xService' of constructor 'Void .ctor(.....
Now this is straight forward enough to understand. The newly added parameter XService can't be resolved...
The error is thrown by Autofac.core.dependency but I am not sure where / how I would register my new object for Autofac.
I understand you have no clue how my project is setup so I'm just looking for greater understanding of what is going on thus enabling me to track down where I need to register my new service object with Autofac etc.
FWIW:
Controller for new section of the site:
public partial class NewSectionController : BaseController
{
private readonly IPL_XService _pl_xService;
#region Constructors
public NewSectionController(IPL_XService pl_xService,....)
{
this._pl_forumService = pl_forumService;
}
.....controller actions, helpers, utilities etc.........
}
Since I am in waters I have not spent much time (if any really) in please let me know of any other code, style, architecture etc. that I can post to help make the question better.
Thank You
Just search for ContainerBuilder class, and then add this code:
var builder = new ContainerBuilder();
builder.RegisterType<PL_XService>().As<IXService>().InstancePerHttpReques‌​t();

Place to put Database.SetInitializer

I'm working on a project that at can end up with multiple UI versions / variants, but so far I've got two subprojects in my solution Web - containing Web interface with ASP.NET MVC. Service project is place where I have my database context and models defined.
My Goal is to have minimum or possibly no references to EF specific code in my Web project. I want it to be independent so when I switch the dlls with service backend ( from let say SQL to XML or MySQL ) I shouldn't make multiple modifications in my MVC project.
This is how it looks :
My Questions are:
- so far I've found no example of using Database.SetInitializer in other place than Global.asax. I'd like to put database re-creation if model changed in my factory-like DatabaseContextProvider class or in service class that pulls out data from context and provides it to the UI with DTOs. Are there any cons of that location ?
- I would like to have the context's connectionString to be configurable with Properties/Settings.settings file - is that reasonable ?
To avoid the coupling, I would prefer not to set the initializer outside the Assembly that contains the DataContext. So, I added a static constructor for the DataContext. This way every project referencing this Assembly will enjoy the initializer without explicitly setting it, and the initializer is set only once per process.
static MyDataContext()
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDataContext, Configuration>());
}
The connection string will of course be taken from the application configuration file.
You would need a mechanism to call the Database.SetInitializer method before the very first usage of the DbContext. That is why its usually called in the Global.asax file.
You can create a class with an initialization method in your tm.Service project and call it in the Application_Start method and put the Database.SetInitializer in that initialization method.
Its OK to supply the connection string from a setting file.
I put it on the DbContext constructor and works for me.
public myDbContext() : base(connectionToDatabase) {
Database.SetInitializer<myDbContext>(null);
}
The solution above will work, but it is not as efficient as the following code:
protected void Application_Start()
{
Database.SetInitializer<myDbContext>(null);
}
In my case I don't have a reference of my DAL on the UI and for that reason what I did is, I create a EntityFramework config and register my setting using using reflection.
protected void Application_Start()
{
EntityFrameworkConfig.RegisterSettings();
}
public static class EntityFrameworkConfig
{
public static void RegisterSettings()
{
// Use the file name to load the assembly into the current
// application domain.
Assembly a = Assembly.Load("MyAssembly");
// Get the type to use.
Type myType = a.GetType("MyType");
// Get the method to call.
MethodInfo myMethod = myType.GetMethod("MySettingsMethod");
// Create an instance.
object obj = Activator.CreateInstance(MyType);
// Execute the method.
myMethod.Invoke(obj, null);
}
}
public void Configurations()
{
//Other settings
Database.SetInitializer<myDbContext>(null);
}
Updated
With Entity Framework 6, now you can use the NullDatabaseInitializer
Database.SetInitializer(new NullDatabaseInitializer<MyDbContext>());
Microsoft made it possible, for EF6 onwards, to configure one initializer per database context in the config file of the application. See the last section on this Microsoft page: https://msdn.microsoft.com/en-us/data/jj556606.aspx
This, like the "Global.asax" approach, has the advantage that e.g. unit test projects can use a different initializer for the same database context.
Click Global.asax page and you find a Application_Start() method.Inside this method past this following code.For support this code use namespace using System.Data.Entity;
Database.SetInitializer<namespace.modelclass>(null);

Custom attributes in C#

I have a custom attribute for my page like this:
[PageDefinition("My page", "~/Parts/MyPage.aspx")]
My PageDefinition looks like this, where AttributeItemDefinitions is get set for Title, Url, IsPage and IsUserControl
public class PageDefinition : AttributeItemDefinitions
{
public PageDefinition(string title, string url)
: this()
{
Title = title;
Url = Url;
}
public PageDefinition()
{
IsPage = true;
IsUserControl = false;
}
}
But i can't find any good way to add all page with that attribute to a placeholder where all links should be list with the title and url. Do you have any good idea? Thanks for your help.
When I've created such custom attributes that define some metadata on a class I've often built a small routine that scans all classes of an assembly using reflection.
In my current project I'm using a IoC framework (other story) and instead of configuring it in a custom config file I've built myself a ComponentAttribute that defines what interface a class belongs to. (From a bird's eye view: I ask the IoC framework for a interface later on and it knows how to instantiate classes that implement that and how they fit together)
To configure that IoC framework I need to call a member of a certain class and tell it which class to interface mappingts exist.
ioc.ConfigureMapping(classType, interfaceType)
To find all those mappings I use the following two methods in one of my helper classes
internal static void Configure(IoCContainer ioc, Assembly assembly)
{
foreach (var type in assembly.GetTypes())
AddToIoCIfHasComponentAttribute(type, ioc);
}
internal static void AddToIoCIfHasComponentAttribute(Type type, IoC ioc)
{
foreach (ComponentAttribute att in type.GetCustomAttributes(typeof(ComponentAttribute), false))
{
ioc.ConfigureMapping(attribute.InterfaceType, type);
}
}
What I'm doing here is enumerating all of an assemblies' types in the first method, and than evaluting the attribute in the second one.
Back to your problem:
Using a similar approach you could find all the marked classes and record them in a container (ArrayList or similar) along with all the data you have defined in the attribute (Page path, etc.).
Update (Answer to comment)
When you build your program in Visual Studio you normally have one or more projects. For each project you will get a distinct assembly (.dll or .exe file). The code above will examine all the classes within one assembly. Seen that way an assembly is a collection of collected .cs files. So you want to search an assembly, not a directory of .cs files (which are source code and not part of the running application.)
So what's probably is missing: How can you access an assembly from your code when you want to search for classes? You just take ANY class you know (that is in the assembly/project where your other classes are) and obtain the assembly it is in by calling
var assembly = typeof(MyDummyClass).Assembly;
and afterwards you'd call something you derived from the code above
AnalyzeClasses(assembly)
and AnalyzeClasses would look like
internal static void AnalyzeClasses(Assembly assembly)
{
foreach (var type in assembly.GetTypes())
AnalzyeSingleClass(type);
}
internal static void AnalzyeSingleClass(Type type)
{
foreach (MyCustomAttribute att in type.GetCustomAttributes(typeof(MyCustomAttribute), false))
{
Console.WriteLine("Found MyCustomAttribute with property {0} on class {1}",
att.MyCustomAttributeProperty,
type);
}
}
And you'd just call all that before you run your application code, for example right
at the top in main() (for applications) or if it's difficult in advanced you can also
call this on demand when you need the collected data. (For example from an ASP.NET page)
It might be more than you need but...
I run into this pattern all of the time in my projects so I implemented a type loader that can be supplied with user defined delegates for a type search matching.
http://www.codeproject.com/KB/architecture/RuntimeTypeLoader.aspx

Categories