MEF and loading EntityTypeConfiguration in runtime - winforms

You cannot vote on your own post
0
Hi.
I am developing this (http://arg-co.com/SabteNam%20-%20Copy.zip) windows application, and for my DAL I use Entity Framework. But every single extension has its own EntityTypeConfiguration, so I decided to use [Import] and [Export] to add them in OnModelCreating method of my DbContext.The problem here is that, in 'SabteNamDbContext' class which is located on 'SabteNamDataAccess' library, the '_Configs' is not initialized so I cant iterate it and add its items to 'modelBuilder.Configurations'.
In the source code of 'SampleConfiguration' class, I commented out '[Export(typeof(IDbConfiguration))]' but even Uncommenting this part of code, do not cause application to work properly.
Intresting point is that, if I use the following code in 'Main' windows form, the '_Configs' would be initialized :
[ImportMany(typeof(IDbConfiguration))]
public IEnumerable<EntityTypeConfiguration<object>> _Configs { get; set; }
How can this be fixed ?

While I realize this is probably no longer of use to you, we use a variation on this model from OdeToCode, which I advise you read.
In our case, we have created an interface for our extensions in general, not just for the entity configuration like Scott did, which allows us not only to load the configurations, but also factory and test data per extension, add new permission types to the core application, etc.
Our OnModelCreating looks something like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// load core object mappings
modelBuilder.Configurations.Add(new UserConfiguration());
modelBuilder.Configurations.Add(new PermissionConfiguration());
// get plugin assemblies
var catalog = new DirectoryCatalog("bin");
var container = new CompositionContainer(catalog);
container.ComposeParts();
var plugins = container.GetExportedValues<IPlugin>();
// load plugin object mappings
foreach (IPlugin plugin in plugins)
{
plugin.RegisterDomainEntities(modelBuilder.Configurations);
}
base.OnModelCreating(modelBuilder);
}

Related

Nancyfx localization

I'm testing localization in Nancy and able to get it to work using EMBEDDED resource files but the issue is I don't want embedded resource files because I want them to be allowed to be edited via the GUI or using the file (if I go the DB route or setting the resource file as "content").
According to the doucmentation you should be able to override it to support using a database but I'm unable to get this to work (https://github.com/NancyFx/Nancy/wiki/Localization):
public class ResourceManager : ResourceBasedTextResource
{
public ResourceManager(IResourceAssemblyProvider resourceAssemblyProvider) : base(resourceAssemblyProvider)
{
}
public new string this[string key, NancyContext context]
{
get
{
return "HELO!";
}
}
}
This was just me messing around but I was hoping in the Razor view when I did #Text.Localization. it should return "HELO!" for everything... however it is not working
There really isn't a question in your post so I'm going to have to guess a bit and assume that you're not getting any exception but rather you're not seeing the "HELO!" in your view
Simply implementing a new ResourceBasedTextResource class is not enough. This is a core component and as such you are going to explicitly have to tell Nancy to use it. You do this by overriding the InternalConfiguration property of your Bootstrapper and tell Nancy to use your implementation instead
You can see it in the DemoBootstrapper of the demo that is linked from that wiki page https://github.com/NancyFx/Nancy/blob/8970ac9d6c7cf46e6060f0b83117c19fa18085c2/src/Nancy.Demo.Razor.Localization/DemoBootstrapper.cs#L11
Also, if you are not going to use resource files, then you should look into inheriting from ITextResource interface instead. It's a simple interface so it should be straight forward.
HTH

MEF can't find module's views when dll in subdirectory

I try to make a little application with Prism and MEF in order to learn how it works. I'm stuck on a fairly frustrating problem.
I would like to have a "Modules" subdirectory in my base app directory where I copy all the module's dll as a post build event.
These modules are MVVM app with View and ViewModel.
My problem is : When I copy my module's dll in the main app directory, the views are displayed in the shell, but when my modules are in the subdirectory, nothing is displayer.
My modules and their parts are found but according to fuslogvw the views can't be found :
* Assembly Binder Log Entry (27/11/2015 # 16:45:28) *
The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.
Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable C:\Users\mouarf\Downloads\Prism-Samples-Wpf-master\Prism-Samples-Wpf-master\HelloWorld\HelloWorld\bin\Debug\HelloWorld.vshost.exe
--- A detailed error log follows.
=== Pre-bind state information ===
LOG: DisplayName = ModuleB.resources, Version=1.0.0.0, Culture=en-US, PublicKeyToken=null
(Fully-specified)
LOG: Appbase = file:///C:/Users/mouarf/Prism/HelloWorld/bin/Debug/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = HelloWorld.vshost.exe
Calling assembly : ModuleB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in LoadFrom load context.
WRN: Native image will not be probed in LoadFrom context. Native image will only be probed in default load context, like with Assembly.Load().
LOG: Using application configuration file: C:\Users\mouarf\Downloads\Prism-Samples-Wpf-master\Prism-Samples-Wpf-master\HelloWorld\HelloWorld\bin\Debug\HelloWorld.vshost.exe.Config
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/Users/mouarf/Prism/HelloWorld/bin/Debug/en-US/ModuleB.resources.DLL.
LOG: Attempting download of new URL file:///C:/Users/mouarf/Prism/HelloWorld/bin/Debug/en-US/ModuleB.resources/ModuleB.resources.DLL.
LOG: Attempting download of new URL file:///C:/Users/mouarf/Prism/HelloWorld/bin/Debug/en-US/ModuleB.resources.EXE.
LOG: Attempting download of new URL file:///C:/Users/mouarf/Prism/HelloWorld/bin/Debug/en-US/ModuleB.resources/ModuleB.resources.EXE.
LOG: Attempting download of new URL file:///C:/USERS/Mouarf/PRISM/HELLOWORLD/BIN/DEBUG/MODULES/en-US/ModuleB.resources.DLL.
LOG: Attempting download of new URL file:///C:/USERS/Mouarf/PRISM/HELLOWORLD/BIN/DEBUG/MODULES/en-US/ModuleB.resources/ModuleB.resources.DLL.
LOG: Attempting download of new URL file:///C:/USERS/Mouarf/PRISM/HELLOWORLD/BIN/DEBUG/MODULES/en-US/ModuleB.resources.EXE.
LOG: Attempting download of new URL file:///C:/USERS/Mouarf/PRISM/HELLOWORLD/BIN/DEBUG/MODULES/en-US/ModuleB.resources/ModuleB.resources.EXE.
LOG: All probing URLs attempted and failed.
I don't know why MEF look in "modules\en-US\", I think it's probably why it doesn't find any views, but I couldn't find how to specify otherwise.
My bootstrapper :
public class Bootstrapper : MefBootstrapper
{
protected override void ConfigureAggregateCatalog()
{
base.ConfigureAggregateCatalog();
this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Bootstrapper).Assembly));
string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Modules");
DirectoryCatalog catalog = new DirectoryCatalog(path, "*.dll");
this.AggregateCatalog.Catalogs.Add(catalog);
}
protected override DependencyObject CreateShell()
{
return this.Container.GetExportedValue<MainWindow>();
}
protected override void InitializeShell()
{
base.InitializeShell();
Application.Current.MainWindow = (MainWindow)this.Shell;
Application.Current.MainWindow.Show();
}
protected override void ConfigureContainer()
{
base.ConfigureContainer();
}
protected override IModuleCatalog CreateModuleCatalog()
{
return new ConfigurationModuleCatalog();
}
}
My modules :
[ModuleExport(typeof(ModuleAModule))]
public class ModuleAModule : IModule
{
IRegionManager _regionManager;
[ImportingConstructor]
public ModuleAModule(IRegionManager regionManager)
{
_regionManager = regionManager;
}
public void Initialize()
{
_regionManager.RegisterViewWithRegion(RegionNames.RightRegion, typeof(ViewA));
}
}
My views :
/// <summary>
/// Interaction logic for ViewA.xaml
/// </summary>
[Export]
public partial class ViewA : UserControl
{
public ViewA()
{
InitializeComponent();
}
}
My viewmodels :
[Export]
public class ViewAViewModel : BindableBase
{
private string _title = "Module A";
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
}
Anyone ?
Edit :
Here's the solution for who whould like to take a look : HelloWorldPrismMef
Edit 2 :
The investigation still goes on, I discovered the really handy mefx ! So my problem seems to be :
[Part] ModuleA.ModuleAModule from: DirectoryCatalog (Path="Modules")
[Primary Rejection]
[Export] ModuleA.ModuleAModule (ContractName="Prism.Modularity.IModule")
[Import] ModuleA.ModuleAModule..ctor (Parameter="regionManager", ContractName="Prism.Regions.IRegionManager")
[Exception] System.ComponentModel.Composition.ImportCardinalityMismatchException: No exports were found that match the constraint contract name
ContractName Prism.Regions.IRegionManager
RequiredTypeIdentity Prism.Regions.IRegionManager n'a été trouvée.
at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition, AtomicComposition atomicComposition)
at Microsoft.ComponentModel.Composition.Diagnostics.CompositionInfo.AnalyzeImportDefinition(ExportProvider host, IEnumerable`1 availableParts, ImportDefinition id)
Does that mean that I need to Export a IRegionManager class ?
The log you have posted is for an attempt to load a resource .dll, something that MEF will never load (resource .dlls are used to store application resource information, like strings for internationalization). You should look for errors that do not mention resource .dlls.
Also, it seems to me you are attempting to edit the Prism Library HelloWorld example from GitHub. This particular example has tight coupling with ModuleA (by that I mean that ModuleA is used as a project dependency in HelloWorld) and to my knowledge you can not simply move the ModuleA.dll from the main folder to a modules folder and expect it to work.
My suggestion would be to add a new project, set that to output to a modules folder and see if that loads (leaving the ModuleA project alone). Or you could remove the reference from the HelloWorld project and use the post build event.
Now regarding the loading of modules from a directory, in my humble opinion, you are over complicating it. All you need is
AgregateCatalog.Catalogs.Add(new DirectoryCatalog(#".\Modules"));
Or presuming you have a convention that specifies a pattern for module file names that resembles AppName.Modules.[ModuleNameHere].dll (eg: AppName.Modules.LoginModule.dll you could use something like this to load the modules
AgregateCatalog.Catalogs.Add(new DirectoryCatalog(#".\Modules", "AppName.Modules.*Module.dll"));
Although this does not seem the case here, if you ever try to load modules from a zone deemed as untrustworthy, the default security policy is to ignore the module. This would happen if you attempt to run the application over a network connection like Windows Share. For this scenario you need to add these instructions to App.config
<runtime>
<loadFromRemoteSources enabled="true" />
</runtime>
These should be added after <startup /> section.
Hope this helps you.
Edit:
Does that mean that I need to Export a IRegionManager class ?
No, that's just complaining because mefx has not loaded the assembly that exports it (Prism.Wpf.dll I think it is called).
Personally I found mefx.exe to be cumbersome; I prefer the GUI version
Now regarding your code, I took a look at the GitHub repository and made some changes but not that many (had some issues with references with ModuleC so I had to remove and add again Prism.Mef & company):
Removed the PostBuildEvent from Infrastructure project
Changed the PostBuildEvent from the module projects. This needs some explaining:
all macros come appended with the directory delimiter "\" so you do not need to add it (I am reffering to $(OutDir)\Modules => $(OutDir)Modules).
COPY/XCOPY require the destination path to end with a delimiter or the destination path will be intepreted as a destinaiton directory ( $(OutDir)Modules => *$(OutDir)Modules* ).
Destination directory needs to exist (so first command should be MKDIR)
I also commented (lines that start with REM are comments) out the command that copies the .pdb because I do not think it is needed and added the /z flag to XCOPY.
Added ILoggerFacade as a dependency to demonstrate that the modules actually load. If you run the application from the Visual Studio Debugger, you will see some messages in the debug window.
Added <loadFromRemoteSources enabled="true" /> in App.config => <configuration /> => <runtime /> so I can run the app over a mounted partition where the project is stored.
All of this is in the PR.
Now regarding why it will not auto-display the views in the regions, I can not say yet. I will keep investigating during my free time, but you might have better luck asking Brian Lagunas as he is one of the developers of Prism.
Edit 2:
As I was looking at Brian Lagunas's profile I saw he answered this post that luckily solves the issue.
Will also add a PR to GitHub.

Registering Startup Class In Nancy Using AutoFac Bootstrapper

I've been reading through a lot of the Jabbr code to learn Nancy and trying to implement many of the same patterns in my own application. One of the things I can't seem to get working is the concept of an on application start class. The Jabbr code base has an App_Start folder with a Startup.cs file (here) in it with the following implementation.
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
...
SetupNancy(kernel, app);
...
}
}
private static void SetupNancy(IKernel kernel, IAppBuilder app)
{
var bootstrapper = new JabbRNinjectNancyBootstrapper(kernel);
app.UseNancy(bootstrapper);
}
When I tried to do something similar to that in my project the Startup.cs file was just ignored. I searched the Jabbr code base to see if it was used anywhere but I wasn't able to find anything and the only differences I could see is Jabbr uses Ninject while I wanted to use AutoFac
Is there a way to register a startup class in nancy?
Take a look at my project over on GitHub, you'll be interested in the Spike branch and may have to unload the ChainLink.Web project to run I can't remember.
I had some trouble finding a way to configure the ILifetimeScope even after reading the accepted answer here by TheCodeJunkie. Here's how you do the actual configuration:
In the bootstrapper class derived from the AutofacNancyBootstrapper, to actually configure the request container, you update the ILifetimeScope's component registry.
protected override void ConfigureRequestContainer(
ILifetimeScope container, NancyContext context)
{
var builder = new ContainerBuilder();
builder.RegisterType<MyDependency>();
builder.Update(container.ComponentRegistry);
}
The application container can be updated similarly in the ConfigureApplicationContainer override.
You should install the Nancy.Bootstrappers.Autofac nuget, inherit from the AutofacNancyBootstrapper type and override the appropriate method (depending on your lifetime scope requirements: application or request). For more info check the readme file https://github.com/nancyfx/nancy.bootstrappers.autofac
HTH
After following the advice from TheCodeJunkie you can use the Update method on the ILifetimeScope container parameter which gives you a ContainerBuilder through an Action:
protected override void ConfigureRequestContainer(ILifetimeScope container, NancyContext context)
{
container.Update(builder =>
{
builder.RegisterType<MyType>();
});
}

Silverlight client, datacontract, and private readonly members

I have a Silverlight client and a WCF service that I want to have share a class:
[DataContract]
public class DatesAreFun
{
[DataMember]
private readonly DateTime _date;
[DataMember]
private readonly bool _isFun;
public DateTime DateTime { get { return _date; } }
public bool IsFun { get { return _isFun; } }
public DatesAreFun(DateTime date, bool isFun)
{
_date = date;
_isFun = fun;
}
}
The WCF side seems to send the appropriate data across the wire just fine, but the Silverlight side doesn't like it one bit. It is treating the WCF service DatesAreFun class as a different class than my DatesAreFun class.
Any suggestions on how best to remedy this? Thanks!
This is a common issue and has been covered here more than a few times.
When you add your service reference, make sure you click the Advanced button, then ensure you have ticked the Reuse types in referenced assemblies checkbox, and selected the Reuse types in all referenced assemblies option.
You also have to create a new class library assembly that targets the Silverlight runtime. This is because the class library referenced by the WCF services will target the full (or maybe the client profile) version of the .Net framework, which a Silverlight assembly cannot do (in fact a Silverlight assembly can only reference other Silverlight targeted assemblies). In your new class library you can reference the same physical files that the full version of the class library is using, this is detailed more here (i had the same question once upon a time...). You could also pick your way through this bunch of search results for related questions.
Depending on how you do things you may find you also have to trawl through the Reference.cs file of the Service Reference, and change the namespaces of the named data entities. (This file will get regenerated if you update or reconfigure the service reference).

Using Castle.Windsor with Windows Forms Applications

Up until this point, I have been learning IoC/DI with Castle.Windsor using ASP.NET MVC, but I have a side project that is being done in Windows Forms, and I was wondering if there is an effective way to use it for that.
My problem is in the creation of forms, services, etc. In ASP.NET MVC, there is a sort of 'Activator' that does this under the hood, but this isn't the case in Windows Forms. I have to create a new Form like var form = new fclsMain();, so a Form like ..
class fclsMain : System.Windows.Forms.Form
{
private readonly ISomeRepository<SomeClass> someRepository;
fclsMain(ISomeRepository<SomeClass> someRepository)
{
this.someRepository = someRepository;
}
}
Falls kind of short. I would basically have to do ...
var form = new fclsMain(IoC.Resolve<ISomeRepository<SomeClass>);
Which as I have had pointed out in at least three of my questions isn't smart, because it's supposedly not the 'correct' usage of IoC.
So how do I work with Castle.Windsor and Windows Forms? Is there some way to design a Form Activator or something? I'm really lost, if I can't make a static IoC container that I can resolve from, what can I do?
Here you are doing something that are not very "Dependency Injection"...
var form = new fclsMain(IoC.Resolve<ISomeRepository<SomeClass>);
The "new" is the problem...
You have to call
var form = IoC.Resolve<fcls>();
the form of type fcls must be correctly configured via Fluent Registration API o
In order to use the same Castle container throughout your entire application, create a static class like:
public static class CastleContainer {
private static IWindsorContainer container;
public static IWindsorContainer Instance {
get {
if (container == null) {
container = new WindsorContainer();
}
return container;
}
// exposing a setter alleviates some common component testing problems
set { container = value; }
}
// shortcut to make your life easier :)
public static T Resolve<T>() {
return Instance.Resolve<T>();
}
public static void Dispose() {
if (container != null)
container.Dispose();
container = null;
}
}
Then register/install all your components in the Main() method. You can also hook into the application shutdown event to call Dispose() (although this isn't critical).
Castle actually uses a Windows Forms app in their quick-start guide.
Edit:
The pattern I showed above is a variant of the service locator, which some people refer to as an anti-pattern. It has a bad reputation because, among other reasons, it liters your code base with references to Windsor. Ideally, you should only have a single call to container.Resolve<...>() to create your root form. All other services & forms are injected via constructors.
Realistically, you'll probably need a few more calls to Resolve, especially if you don't want to load every single corner of the application at startup. In the web world, the best practice is to hand off the container to the web framework. In the Windows Forms world you'll need to implement your own service locator, like above. (Yes, handing the container to the ASP.NET MVC framework is still a service locator pattern).
I've edited the above code example so that the static container is injectable; no resources are tied up in a static context. If you do end up creating your own service locator, you might also want to create a test utility like this one to make testing easier.
public static class TestUtilities
{
public static IContainer CreateContainer(Action<IContainer> extraConfig = null)
{
var container = new WindsorContainer();
// 1. Setup common mocks to override prod configuration
// 2. Setup specific mocks, when provided
if (extraConfig != null)
extraConfig(container);
// 3. Configure container with production installers
CastleContainer.Instance = container;
return container;
}
}
This makes a shortcut for creating a new container that looks a lot like the production version, but with some services replaced with mocks. Some example tests might look like:
[Test]
public void SubComponentWorksGreat()
{
using (var container = TestUtilities.CreateContainer())
{
var subComponent = container.Resolve<SubComponent>();
// test it...
}
}
[Test]
public void SubComponentWorksGreatWithMocks()
{
var repoMock = new Mock<IRepository>();
using (var container = TestUtilities.CreateContainer(c =>
c.Register(Component.For<IRepository>().Instance(repoMock.Object))))
{
var subComponent = container.Resolve<SubComponent>();
// test it with all IRepository instances mocked...
}
}
One last note. Creating a full container for every test can get expensive. Another option is to create the full container but only using nested containers for the actual tests.
You don't "have to" new-up a form, as you've said.
I use WinForms and never call "new FormName()". It's always a dependency itself. Otherwise I'd have to stuff the constructor full of service locator calls.
I might use a ServiceLocator (as in another answer) BUT only at the very top level.
For example I have a Command pattern implemented to intercept toolbar buttons.
Looks something like this:
public void Handle(string commandName)
{
var command = IoC.Resolve<ICommand>(RegisteredCommands[commandName]);
command.Execute();
}
Then, in a simplified case, this is the kind of code written everywhere else:
public class ShowOptionsCommand : Command, ICommand
{
private readonly IOptionsView _optionsView;
public ShowOptionsCommand(IOptionsView optionsView)
{
_optionsView = optionsView;
}
public void Execute()
{
_optionsView.Show();
}
}
Yes, I use a "service locator" but you will hardly ever see it.
That's important to me, because having service locator calls all throughout the code (eg in every class) defeats some of the point of using dependency inversion of control & needs extra work to be testable etc

Resources