I am using C# 4.7.2 an PRISM Unity 6.2.0
I got a public class like this
public partial class MyClass
{
public static string MyFirstString = "MyFirstString";
public static string MySecondString = "MySecondString";
}
The strings are used to register types
public void Initialize()
{
RegisterObjects();
}
private void RegisterObjects()
{
container.RegisterType<object, SomeClass>( MyClass.MyFirstString );
container.RegisterType<object, SomeOtherClass>( MyClass.MySecondString );
}
container is an IUnityContainer, Initiliaze() is a member of IModule (from PRISM)
SomeClass is registered without any problems. But SomeOtherClass can not be registered. A System.MissingFieldException is thrown on MyClass.MySecondString.
Everything is public, the build succeeds, one can even navigate to MySecondString by pressing F12 (in Visual Studio).
What could cause this exception?
It sounds like you have multiple versions of the DLL loaded in your cache. Use "gacutil -l " to see how many version are loaded in your cache. You can use "gacutil -u " to remove all versions.
Related
I'm currently using Visual Studio Mac 2019 for to build my iOs Xamarin Forms Application.
My Application Akavache to store persistent data specifically credentials which I utilizes its BlobCache.Secure storage, but sadly the data doesn't persist.
I found that I should add either of the following:
1. Linker Class
using System;
using Akavache.Sqlite3;
namespace NameSpace.iOS
{
[Preserve]
public static class LinkerPreserve
{
static LinkerPreserve()
{
var persistentName = typeof(SQLitePersistentBlobCache).FullName;
var encryptedName = typeof(SQLiteEncryptedBlobCache).FullName;
}
}
public class PreserveAttribute : Attribute
{
}
}
or
2. Initializer
Akavache.Registrations.Start("FollowTheDrop");
Akavache: saved value not available after iOS app restart
but every time I add the solution above the following error below occurs during the build
MTOUCH : error MT2101: Can't resolve the reference 'System.Int32
SQLitePCL.raw::sqlite3_bind_blob(SQLitePCL.sqlite3_stmt,System.Int32,System.Byte[])',
referenced from the method 'System.Void
Akavache.Sqlite3.BulkInsertSqliteOperation/<>c__DisplayClass7_0::b__0()'
in 'SQLitePCLRaw.core, Version=1.1.13.388, Culture=neutral,
PublicKeyToken=1488e028ca7ab535'.
Am I missing something that causes this error?
It was solved by updating the following Nuget Packages below which has dependencies on each other:
Akavache 9.0.1
Splat 14.3.1
fusillade 2.4.47
Lastly when adding the linker static class consider adding a Preserve Attribute as shown below:
[Preserve]
public static class LinkerPreserve
{
static LinkerPreserve()
{
var persistentName = typeof(SQLitePersistentBlobCache).FullName;
var encryptedName = typeof(SQLiteEncryptedBlobCache).FullName;
}
}
public class PreserveAttribute : Attribute
{
}
I have a DLL MyAssemblyOne.dll which only contains one class with static methods:
namespace MyAssemblyOne
{
public class MyClassOne
{
public static string MyStaticMethod()
{
...
}
}
}
All is good so far, the assembly MyAssemblyOne.dll is generated.
Now I have another DLL, MyAssemblyTwo.dll which has a dependency on MyAssemblyOne.dll and uses it like:
no using here;
namespace MyAssemblyTwo
{
public class MyClassFromAssemblyTwo
{
public string SomeRandomMethod()
{
...
var smth = MyAssemblyOne.MyClassOne.MyStaticMethod();
...
}
}
}
Now I create a Xamarin project with Linking set to Sdk Assemblies Only and Use Shared Runtime disabled(basically Release mode), and I add my two DLLs - MyAssemblyTwo.dll and MyAssemblyOne.dll. The app builds ok, but when I run it I get something like:
cannot find MyAssemblyOne.dll.
Please note that this works if the Linking option is set to None.
However, if I change MyAssemblyTwo usage of MyAssemblyOne to be:
using MyAssemblyOne;
namespace MyAssemblyTwo
{
public class MyClassFromAssemblyTwo
{
public string SomeRandomMethod()
{
...
var smth = MyClassOne.MyStaticMethod();
...
}
}
}
everything works fine even with the Linking set to Sdk Assemblies Only.
How does the linker work? Why if I have a using statement everything is fine, but if I use the assembly name directly in the code it breaks.
It is worth mentioning that MyAssemblyOne and MyAsseblyTwo are .netstandard20 projects.
I'm just taking my first baby steps in the MEF territory and wanted to do so using .net core 2.1.
Using VS 2017 (version 15.8.8) I've done a small Console App (.NET Core) with an interface
interface IMessageSender
{
void Send(string message);
}
and an implementation (in the same project)
[Export(typeof(IMessageSender))]
public class EmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine("EmailSender : " + message);
}
}
Finally I have a small compose method executed from my Main(string[] args)
[Import]
private void Compose()
{
var assembly_A = new[] { typeof(Program).GetTypeInfo().Assembly };
var config_A = new ContainerConfiguration().WithAssembly(assembly_A[0]);
var container_A = config_A.CreateContainer();
var msg_A = container_A.GetExport<IMessageSender>();
msg_A.Send("Hello");
}
It works as expected
However, if I add a new class library to my solution and move my implementation of Send(string) to the newly added project things do not work out.
namespace AnotherMefExtensionProjectNamespace
{
[Export(typeof(IMessageSender))]
public class EmailSenderExtended : IMessageSender
{
public void Send(string message)
{
Console.WriteLine("EmailSenderExtended : " + message);
}
}
}
The new Compose method
[Import]
public IMessageSender MessageSender { get; set; }
private void Compose()
{
var assembly_B = new[] { typeof(EmailSenderExtended).GetTypeInfo().Assembly };
var config_B = new ContainerConfiguration().WithAssembly(assembly_B[0]);
var container_B = config_B.CreateContainer();
var msg_B = container_B.GetExport<IMessageSender>();
msg_B.Send("Hello");
}
I've tried to compare the different configs and containers (_A versus _B in the examples) but can't understand what is different. I've even tried to extend the class ContainerConfiguration to load from a specified assembly and it works as long as the given file contains the Main method but fails if I use my "extended" .NET Core Class Library.
public static ContainerConfiguration WithChosenAssembly(this ContainerConfiguration configuration, string pathAndFile)
{
var context = AssemblyLoadContext.Default.LoadFromAssemblyPath(pathAndFile);
var ass_list = new List<Assembly>() { context };
configuration = configuration.WithAssemblies(ass_list, null);
return configuration;
}
I was under the impression that you extend your main application by developing a class library that basically implements the interfaces specified.
I seem to be unable to do this currently, but obviously I misunderstood something very basic.
If someone would care to put me on the right track or give me an alternative idea for "plug-in" development for .net core I would be very grateful.
King regards
Magnus
I realized that my test setup does not mimic any real world scenario and thus I brought my problems on myself.
Obviously I should have had three projects.
One project with only the interface definitions.
One "main" project where all my regular code exists.
One (or more) projects where my MEF implementations of the interfaces exist.
Reviewing my example and adhering to the obvious "design" above it all works exactly as it should.
Most StackOverflow users probably wouldn't make my blunder but for those that did, I hope the above helps. :-)
I am being prompted for a file called EnumerableExtensions.cs when using the NHibernateFacility for Castle Windsor. I have replicated this with the following steps (all packages were installed from NuGet):
Create a new WPF project
Install Castle.Core 3.1.0
Install Castle.Windsor 3.1.0
Install Castle.FactorySupportFacility 3.1.0
Install Castle.Transactions 3.2.207.2207
Install Castle.Facilities.AutoTx 3.2.207.2207
Install NHibernate 3.3.1.4000
Install Fluent NHibernate 1.3.0.733
Install Castle.Facilities.NHibernate 0.7.1.23602
Override OnStartup() in App.xaml.cs to create the Windsor container and add the facilities to it. See code below.
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
IWindsorContainer container = new WindsorContainer();
container.AddFacility<AutoTxFacility>();
container.Register(
Component.For<INHibernateInstaller>()
.ImplementedBy<FluentNHibernateInstaller>());
container.AddFacility<NHibernateFacility>();
}
This is the code in FluentNHibernateInstaller.cs
public class FluentNHibernateInstaller : INHibernateInstaller
{
public FluentConfiguration BuildFluent()
{
return Fluently.Configure();
}
private IPersistenceConfigurer SetupDatabase()
{
return MsSqlConfiguration.MsSql2008
.ConnectionString(c => c
.Server("Server")
.Database("Database")
.Username("User")
.Password("Password"));
}
public Maybe<NHibernate.IInterceptor> Interceptor
{
get { return Maybe.None<NHibernate.IInterceptor>(); }
}
public bool IsDefault
{
get { return true; }
}
public void Registered(ISessionFactory factory)
{
}
public string SessionFactoryKey
{
get { return "sf.default"; }
}
}
When I run the application, this is the dialog I am presented with:
To me this looks like something is wrong with the DLL but when I posted about this on the Castle Project Google Group it was suggested that I had incompatible versions of Windsor in my app. Is this true or does it seem like something else is going on?
That dialog is Visual Studio asking for the source code of the file where an exception originated. Click cancel, and Visual Studio will instead stop somewhere in your own code and display the exception.
You can prevent the dialog by removing the pdb-file for the component in which the exception occurs (but that will also lead to less useful stack traces in case you want to report a bug in the affected component).
I have just started using MEF and have hit on an early problem.
I have an interface called DataService:
namespace DataAccess
{
interface IDataService
{
string Name { get; }
string Description { get;}
List<String> GetPeople();
}
}
There are 2 implementations of this interface, one for SQL Server and one for Oracle.
Below is the Oracle implementation, SQL Server implementation is exactly the same.
namespace DataAccess
{
[Export(typeof(IDataService))]
[ExportMetadata("Name","Oracle")]
[ExportMetadata("Description","Oracle Data Service")]
public class Oracle : IDataService
{
#region IDataService Members
public string Name
{
get { return "Oracle"; }
}
public string Description
{
get { return "Provides data access to Oracle database"; }
}
public List<string> GetPeople()
{
return new List<String>() { "Oracle boo", "Oracle boo1" };
}
#endregion
}
}
The name and description properties are now defunct as I have replaced these with metadata. As you can see, they are very simple objects, I wanted to make sure I could get this to work before I started doing the hard work.
This is the code I am using to discover the assemblies:
private static CompositionContainer _container;
private const string ASSEMBLY_PATTERN = "*.dll";
private AggregateCatalog _catalog;
[ImportMany]
IEnumerable<DataAccess.IDataService> services { get; set; }
private void button3_Click(object sender, EventArgs e)
{
_catalog = new AggregateCatalog(
new DirectoryCatalog(txtLibPath.Text, ASSEMBLY_PATTERN),
new AssemblyCatalog(Assembly.GetExecutingAssembly()));
_container = new CompositionContainer(_catalog);
_container.ComposeParts(this);
MessageBox.Show(services.Count().ToString());
}
This is the error that is produced:
The composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information.
1) The export 'DataAccess.Oracle (ContractName="DataAccess.IDataService")' is not assignable to type 'DataAccess.IDataService'.
Resulting in: Cannot set import 'MEFTest.Form1.services (ContractName="DataAccess.IDataService")' on part 'MEFTest.Form1'.
Element: MEFTest.Form1.services (ContractName="DataAccess.IDataService") --> MEFTest.Form1
It doesn't seem to make any sense that it can't assign to the interface that it was designed for!
Once this problem is solved, my next issue is how to pick one and get an instance of it...
It looks like two different versions of your contract assembly (the one with DataAccess.IDataService) are getting loaded. One is probably from your executable path and the other from your plugin path. I touch on this issue a bit in my blog post on How to Debug and Diagnose MEF Failures, and the MSDN page on Best Practices for Assembly Loading goes into more detail.
Yet another cause:
Code:
interface IMyService
{
}
[Export(typeof(IMyService))]
class MyService
{
}
Message:
The export 'IMyService' is not assignable to type 'IMyService'.
Cause:
The MyService class does not implement the IMyService interface.
For me this had a very simple fix.
Here's a link! that explains the root cause.
In my case, I locked my Assembly version down, but my file version travels. My nuget package ID matches my assembly file version.
Final result is that I can build continuously, create new nugets, and not have this MEF inteface problem.
I must tell that I had such an error in completely idiotic context. Accidentally, I misplaced export directive and put it not on class but on a function inside class:
interface MyInterface
{
void MyFunction();
}
public class MyClass : MyInterface
{
[Export(typeof(MyInterface))]
void MyFunction() { }
}
Surprisingly, the code compiled very fine without any warnings. But then I ve spent hours trying to figure out why MEF fails on my silly misprint!