I have a simple IHttpModule
namespace System.Web.Extensions.Resource
{
public class MyHttpModule : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.PreSendRequestContent += PreSend_RequestContent;
}
private void PreSend_RequestContent(object sender, EventArgs e)
{
HttpResponse response = ((HttpApplication)sender).Response;
response.AddHeader("MyHttpModule", "Running");
}
}
}
And I installed it to GAC with powershell (No errors at all):
$name = "c:\MyHttpModule.dll";
[System.Reflection.Assembly]::Load('System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a');
$publish = New-Object System.EnterpriseServices.Internal.Publish;
$publish.GacInstall($name);
$type = 'System.Web.Extensions.Resource.MyHttpModule,' + [System.Reflection.AssemblyName]::GetAssemblyName($name).FullName;
C:\Windows\System32\inetsrv\Appcmd.exe add module /name:MyHttpModule /type:"$type"
But when I access the IIS site, I got
Exception Details: System.IO.FileNotFoundException: Could not load file or assembly 'MyHttpModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
So Windows no longer support installation to GAC cache?
EDIT
I've added a strong name and confirmed the assembly is installed to C:\Windows\Microsoft.NET\assembly\GAC_MSIL\MyHttpModule\v4.0_1.0.0.0__4959579d21f18138.
Now IIS has a different error
System.TypeLoadException: Could not load type 'System.Web.Extensions.Resource.MyHttpModule' from assembly 'MyHttpModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4959579d21f18138'.
But from ILSpy I can see this type is available, so what was wrong then?
EDIT again
It suddenly worked, I've seen the header added by the module. Not sure why, but closing it now.
The PublicKeyToken is null, which mean the DLL is not signed with a strong name. You need to sign the Dll and then put it to GAC, please refer the MSDN article here, the article also tells you how to sign it in VS:
I have an MVC project that has been working for years that I just re-published to the server yesterday. I opened it up to debug and make changes to code. Some time in between compiles, something happened and now the build fails complaining that
The type 'System.Windows.FrameworkElement' is defined in an assembly that is not referenced. You must add a reference to assembly 'PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'.
and
The type 'System.Windows.DependencyObject' is defined in an assembly that is not referenced. You must add a reference to assembly 'WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'.
I have looked at similar questions and done as they have suggested to make sure all files are set to the Build Action compile, content or none for the project. I didn't add any new files and I didn't copy paste any images into solution.
Any ideas?
Edit:
Not sure if this will be helpful. I didn't include it because it doesn't seem like it would be, but this is where it takes me when I double click on the errors given.
public PartialViewResult GetByJobID(int jobID)
{
ViewBag.Jobid = jobID;
var getAllHolesByJobID = _toolCalloutService.getAllJobHoles(jobID);
var toolOrderHoleViewModels = //error happens here on var
getAllHolesByJobID.Select(Mapper.Map<HoleInfoViewModel, ToolOrderHoleViewModel>).ToList();
var shipOrigins = _toolCalloutService.GetDistricts();
ViewData["ToolOrderHoleViewModels"] = toolOrderHoleViewModels;
ViewData["ShipOrigins"] = shipOrigins;
ViewData["OrderedBy"] = System.Web.HttpContext.Current.User.Identity.Name.Substring(9);
return PartialView("~/Views/ToolCallout/ToolCallout.cshtml");
}
It just highlights the var keyword at var toolOrderHoleViewModels.
I have retrycode Logic outside of my application which Loads the Assemblies using Assembly.LoadFile(Asmpath);
and returns the object from the loaded assembly back to the my application.
and i have the reference to the same assembly in app. which i have created using Add Refferences.
i am able to return the object. but while casting the returned object to its type in my application its throwing the following Error:
[A]SampleAssembly1.Class1 cannot be cast to [B]SampleAssembly1.Class1. Type A originates from 'SampleAssembly1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadNeither' at location 'C:\Users\v-saabdu\Desktop\Final Code for RetryMethod\ReflectionSamples\SampleAssembly1\bin\Debug\SampleAssembly1.dll'. Type B originates from 'SampleAssembly1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location 'C:\Users\v-saabdu\Desktop\Final Code for RetryMethod\ReflectionSamples\ReflectionAssembly\bin\Debug\SampleAssembly1.dll'.
from the above error message I understood that the way assemblies are loaded in my application and in retrycode (outside of my app) differning in context.
can any one suggest me solution for this..
Thankx,
Assembly assembly = Assembly.LoadFile("Libtest.dll");
TestLib lib = (TestLib)assembly.CreateInstance("Lib");
lib.doSomething();
Lib class must implement the TestLib interface and must be accessible both from both Foo.dll and bar.dll.
I have a wierd application loading mechanism. I have a boostrapping exe file with all the other DLLs and the application itself inside it's resources. These files (assemblies) are extracted from resources and loaded ond emand because i'm attaching to the Assemblyresolve event of the current AppDomain.
[STAThread]
static void Main()
{
// if the command line contains extract then extract the dlls, next run will resolve assemblies from disk
bool saveDllsToDisk = new List<string>(Environment.GetCommandLineArgs()).Contains("extract");
// if the command line contains bin then use the bin folder instead of temp to extract dlls
bool useBinFolder = new List<string>(Environment.GetCommandLineArgs()).Contains("bin");
if (!Directory.Exists(tempFolder)) {
Directory.CreateDirectory(tempFolder);
}
// the assembly resolver will get here because it will not find the dlls in the bin folder
// we load assemblies in our specific way:
// - if exists in our temp/bin folder load from there
// - else load from resources
// - if specified extract DLLs to the temp/bin folder
AppDomain.CurrentDomain.AssemblyResolve += (sender, args2) =>
{
string name = new AssemblyName(args2.Name).Name;
Debug.WriteLine("START LOADING " + name);
Assembly assembly = null;
string folder = useBinFolder ? binFolder : Path.Combine(tempFolder, APP_NAME);
string fileName = name.Replace(".","_").Replace("#EXE#", ""); // in resources we use _ instead of .
string extension = name.Contains("#EXE#") ? "exe" : "dll"; // hack for our embedded exe files
name = name.Replace("#EXE#", ""); // hack for our embedded exe files
if (File.Exists(Path.Combine(folder,String.Format("{0}.{1}", name, extension))))
{
// load from file in app temp folder
assembly = Assembly.LoadFile(Path.Combine(folder, String.Format("{0}.{1}", name, extension)));
}
else
{
// extract assembly from resources
byte[] assemblyBytes = (byte[])resMan.GetObject(fileName, CultureInfo.InvariantCulture);
assembly = Assembly.Load(assemblyBytes);
// if selected save to file so the next run JIT will resolve from disk
if (saveDllsToDisk)
{
string outDll = Path.Combine(folder, String.Format("{0}.{1}", name, extension));
using (var fs = File.Create(outDll))
{
fs.Write(assemblyBytes, 0, assemblyBytes.Length);
}
}
}
Debug.WriteLine("LOADED " + name);
return assembly;
};
splashScreen = new frmSplash();
// as soon as splashscreen starts animating assembly preloading will be launched on this eventhandler
splashScreen.Started += new EventHandler(splash_Started);
// splashscreen has finished fadein we must now wait for all libraries to be preloaded and set CanContinue
splashScreen.Finishing += new EventHandler(splash_Finishing);
splashScreen.CanContinue = false;
// run splashscreen while preloading of DLLs is going on
Application.Run(splashScreen);
}
This bootstrapper has only one reference and that is to the main application, but it does not reference it in the main method to avoid assembly search at start. What I do is force assembly loading during the splashscreen animation:
ObjectHandle instance;
string[,] assemblies = {
{"WindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35","dummy"}, // will go from GAC, not our resolver
{"PresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35","dummy"}, // will go from GAC, not our resolver
{"PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35","dummy"}, // will go from GAC, not our resolver
{"WindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35","dummy"}, // will go from GAC, not our resolver
{"PresentationFramework.Aero, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35","dummy"}, // will go from GAC, not our resolver
{"System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","dummy"}, // will go from GAC, not our resolver
{"AvalonDock, Version=1.3.3585.0, Culture=neutral, PublicKeyToken=85a1e0ada7ec13e4", "dummy"}, // out reference inside resources
{"AvalonDock.Themes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "dummy"}, // out reference inside resources
{"ICSharpCode.AvalonEdit, Version=4.0.0.5950, Culture=neutral, PublicKeyToken=9cc39be672370310", "dummy"}, // out reference inside resources
{"WPG, Version=2.0.4120.37542, Culture=neutral, PublicKeyToken=null","dummy"}, // out reference inside resources
{"WPGBrushEditor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","dummy"}, // out reference inside resources
{"HLSLEditor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","dummy"} // preload even our main file that will launch after the splashscreen
};
for (int i = 0; i <= assemblies.GetUpperBound(0); i++)
{
try
{
instance = AppDomain.CurrentDomain.CreateInstance(assemblies[i,0], assemblies[i,1]);
}
catch (Exception ex) {
/* must not raise errors, it will fail because we are not actually asking for a
* valid type and we only need this assembly loaded right now*/
}
}
Now you see that there are no actual dll files in any folder but are assemblies directly loaded from resources.
My problem now is: How to register a COM object delared in one of my dll files?
RegAsm uses filepaths to register a COM object... :(
Any help appreciated!
I'm doing something very similar in Excel-DNA. You don't have to deserialize the COM types to disk, or register them in advance. What I did is to define a class that implements IClassFactory, then register it as the current class factory for the particular CLSID (type) by calling CoRegisterClassObject. When COM tries to create the object, your class factory is called and can return an instance of your .NET type.
Depending on the context, you might have to deal with the ProgID / CLSID registration on the fly.
(If you contact me I'd be happy to help you grab the right bits from the Excel-DNA code to get you started.)
I digged a little and maybe implementing DllRegisterServer() intot he main executable and then registering all the COM types in all the embedded DLLs would work...
Can anyone confirm?
EDIT: Yes it can be done, but the main executable must be a COM proxy to the DLLs inside.
I'am building a small plugin architecture (unfortunately MEF is not an options because it needs to run on .NET 2.0).
I want to be able to put dll's in a directory without recompiling the main project.
My main project is a winforms application which has some dialogs to pick an implementation of an interface the main program needs.
I have a method that searches a certain directory and gives a List of locations of the dll's I want to search for Types that implement the interface.
public List<Type> GetPluginTypes()
{
List<Type> types = new List<Type>();
foreach (string dll in this.Plugins)
{
Assembly assembly;
try
{
assembly = AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(dll));
}
catch
{
continue;
}
foreach (Type type in assembly.GetExportedTypes())
{
if (type.IsInterface || type.IsAbstract)
continue;
if (typeof(IMyInterface).IsAssignableFrom(type))
types.Add(type);
}
}
return types;
}
Using this method I show the user a list of implementations, one is chosen and it's AssemblyQualifiedName is saved to a settings file.
When I start the main application, I load the AQN from the settings and load all the plugins into the AppDomain by calling the above method.
string typeName = GetSetting("MyPlugin");
GetPluginTypes(); // just to load the plugins into the app domain
Type.GetType(typeName); // allways returns null.
Here is my problem: Type.GetType(typeName), always returns null.
I used Type.GetType(typeName, true), to enforce an exception, which I got:
Could not load file or assembly 'MyImpl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.":"MyImpl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"}
I am clueless. I've already loaded the assembly into the AppDomain, and still Type.GetType(string) can't find it when I specify the AQN.
This can be solved by registering the AppDomain.AssemblyResolve event for the AppDomain which will request the assembly and make the handler return the already loaded assembly.
Here is what the handler looks like in C#:
private System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
return
AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(Kandidaat => string.Equals(Kandidaat.GetName().FullName, args.Name));
}
a detailed explanation can be found here:
https://msdn.microsoft.com/en-us//library/ff527268(v=vs.110).aspx
appdomain assemblyresolve
Perhaps this is relevant. From the documentation for Type.GetType(String, Boolean):
If typeName includes only the name of
the Type, this method searches in the
calling object's assembly, then in the
mscorlib.dll assembly. If typeName is
fully qualified with the partial or
complete assembly name, this method
searches in the specified assembly.
You said that you try calling with type.AssemblyQualifiedName, but it failed. Did you check the qualified name to see if it was reasonable?