Wednesday, May 2, 2018

c# - Loading dll from resources fails



My application depends on a few DLLs. I put them all in resources and than on start of the application I load them using a method I found on the web:



public static void LoadDllsFromResources()

{
AppDomain.CurrentDomain.AssemblyResolve += (sender, a) =>
{
string dllName = a.Name.Contains(',')
? a.Name.Substring(0, a.Name.IndexOf(','))
: a.Name.Replace(".dll", "");

dllName = dllName.Replace(".", "_");

if (dllName.EndsWith("_resources")) return null;


System.Resources.ResourceManager rm =
new System.Resources.ResourceManager(
"DesktopDashboard" + ".Properties.Resources",
System.Reflection.Assembly.GetExecutingAssembly());

byte[] bytes = (byte[])rm.GetObject(dllName);

return System.Reflection.Assembly.Load(bytes);
};

}


It worked fine for me until I tried to add WPFToolkitExtended.dll. Than my app throws an error. What makes this DLL so special?




System.Windows.Markup.XamlParseException: 'Set connectionId threw an
exception.' Line number '4' and line position '37'. --->
System.InvalidCastException: [A]Xceed.Wpf.Toolkit.BusyIndicator cannot
be cast to [B]Xceed.Wpf.Toolkit.BusyIndicator. Type A originates from

'WPFToolkit.Extended, Version=1.7.4644.13122, Culture=neutral,
PublicKeyToken=3e4669d2f30244f4' in the context 'LoadNeither' in a
byte array. Type B originates from 'WPFToolkit.Extended,
Version=1.7.4644.13122, Culture=neutral,
PublicKeyToken=3e4669d2f30244f4' in the context 'LoadNeither' in a
byte array. at
DesktopDashboard.LogoutWindow.System.Windows.Markup.IComponentConnector.Connect(Int32
connectionId, Object target) at
MS.Internal.Xaml.Runtime.ClrObjectRuntime.SetConnectionId(Object root,
Int32 connectionId, Object instance) --- End of inner exception

stack trace --- at
System.Windows.Markup.XamlReader.RewrapException(Exception e,
IXamlLineInfo lineInfo, Uri baseUri) at
System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader,
IXamlObjectWriterFactory writerFactory, Boolean
skipJournaledProperties, Object rootObject, XamlObjectWriterSettings
settings, Uri baseUri) at
System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader,
Boolean skipJournaledProperties, Object rootObject, XamlAccessLevel
accessLevel, Uri baseUri) at

System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext
parserContext, Object parent, Boolean closeStream) at
System.Windows.Application.LoadComponent(Object component, Uri
resourceLocator) at
DesktopDashboard.LogoutWindow.InitializeComponent() at
DesktopDashboard.LogoutWindow..ctor() at
DesktopDashboard.MainWindow.ContextMenuItemLogout_Click(Object sender,
RoutedEventArgs e) at
System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target,
RoutedEventArgs routedEventArgs) at

System.Windows.EventRoute.InvokeHandlersImpl(Object source,
RoutedEventArgs args, Boolean reRaised) at
System.Windows.UIElement.RaiseEventImpl(DependencyObject sender,
RoutedEventArgs args) at
System.Windows.UIElement.RaiseEvent(RoutedEventArgs e) at
System.Windows.Controls.MenuItem.InvokeClickAfterRender(Object arg)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate
callback, Object args, Int32 numArgs) at
MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object
source, Delegate method, Object args, Int32 numArgs, Delegate
catchHandler) at

System.Windows.Threading.DispatcherOperation.InvokeImpl() at
System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object
state) at System.Threading.ExecutionContext.runTryCode(Object
userData) at
System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode
code, CleanupCode backoutCode, Object userData) at
System.Threading.ExecutionContext.RunInternal(ExecutionContext
executionContext, ContextCallback callback, Object state) at
System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state, Boolean

ignoreSyncCtx) at
System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state) at
System.Windows.Threading.DispatcherOperation.Invoke() at
System.Windows.Threading.Dispatcher.ProcessQueue() at
System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32
msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at
MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam,
IntPtr lParam, Boolean& handled) at
MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o) at

System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate
callback, Object args, Int32 numArgs) at
MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object
source, Delegate method, Object args, Int32 numArgs, Delegate
catchHandler) at
System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority
priority, TimeSpan timeout, Delegate method, Object args, Int32
numArgs) at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd,
Int32 msg, IntPtr wParam, IntPtr lParam) at
MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg) at

System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame
frame) at
System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
at System.Windows.Application.RunDispatcher(Object ignore) at
System.Windows.Application.RunInternal(Window window) at
System.Windows.Application.Run(Window window) at
System.Windows.Application.Run() at
DesktopDashboard.App.Main(String[] args)



Answer



Your code is loading the same assembly more than once. That's a problem when you use Assembly.Load(byte[]), the CLR cannot help you figure out that an assembly was already loaded. The technical term is that such an assembly was loaded without a "loading context". What goes wrong next is that the same type is no longer compatible, type identity includes not just the namspace name and type name but also the assembly it came from.




It is your job to ensure that you return the exact same assembly reference when the same assembly is requested. Best thing to do is to keep a Dictionary that keeps track of such assemblies.


No comments:

Post a Comment

plot explanation - Why did Peaches' mom hang on the tree? - Movies & TV

In the middle of the movie Ice Age: Continental Drift Peaches' mom asked Peaches to go to sleep. Then, she hung on the tree. This parti...