senzacionale
senzacionale

Reputation: 20916

cast problem from class to interface

Assembly assembly = Assembly.LoadFrom("Logic\\bin\\Debug\\Logic.dll");
            Type queryManagerType = assembly.GetType("Logic." + HttpContext.Current.Session["lang_name"] + "SearchQueryManager");
            var queryManager = (ISearchQueryManager)Activator.CreateInstance(queryManagerType);


public interface ISearchQueryManager
    {
        IList<Advertisements> ApplyQueries(string searchQuery, int page, int pageSize, string orderBy, out int count);
    }

public class SlovenianSearchQueryManager : ISearchQueryManager
    {
...
}

but i get

Unable to cast object of type 'Logic.SlovenianSearchQueryManager' to type 'Logic.ISearchQueryManager'.

EDIT: whole stacktrace

System.InvalidCastException was unhandled by user code
Message="Unable to cast object of type 'Logic.SlovenianSearchQueryManager' to type 'Logic.ISearchQueryManager'."
Source="ViaMura.Web.Module"
StackTrace: at ViaMura.Web.Module.WebController.GetAdvertismentsByRawQuery(String rawQuery, Int32 page, Int32 pageSize, String orderBy, Int32& count) in D:\PROJEKTI\crawler\WebCrawlerSuite\ViaMura.Web.Module\WebController.cs:line 32 at ViaMura.Web.Module.Views.SearchResultsPresenter.OnResultsLoad(Int32 page, Int32 pageSize, String orderBy) in D:\PROJEKTI\crawler\WebCrawlerSuite\ViaMura.Web.Module\Views\SearchResultsPresenter.cs:line 43 at ViaMura.Web.SearchResults.SearchAdvertisments() in D:\PROJEKTI\crawler\WebCrawlerSuite\ViaMura.Web\SearchResults.aspx.cs:line 155 at ViaMura.Web.SearchResults.Page_Load(Object sender, EventArgs e) in D:\PROJEKTI\crawler\WebCrawlerSuite\ViaMura.Web\SearchResults.aspx.cs:line 149 at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) at System.Web.UI.Control.OnLoad(EventArgs e) at ViaMura.Web.App_Code.PageControllers.BasePage.OnLoad(EventArgs e) in D:\PROJEKTI\crawler\WebCrawlerSuite\ViaMura.Web\App_Code\PageControllers\BasePage.cs:line 89 at System.Web.UI.Control.LoadRecursive() at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
InnerException:

EDIT2:

string a1 = typeof (ISearchQueryManager).Assembly.Location;
string a2 = typeof(SlovenianSearchQueryManager).Assembly.Location

give me the same result:

C:\Windows\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\5438a399\53975f83\assembly\dl3\0f9540b5\15407fe2_5db7cb01\Logic.DLL

but

string a3 = queryManagerType.Assembly.Location;

gives me different path:

D:\PROJEKTI\crawler\WebCrawlerSuite\WebCrawler.Logic\bin\Debug\WebCrawler.Logic.dll

Upvotes: 6

Views: 3764

Answers (5)

Mark
Mark

Reputation: 424

Is the interface defined twice, in two assemblies? This happened to me when I dragged-and-dropped an interface between projects thinking VS would move it, but the interface was actually copied.

I discovered this by looking at the Assembly.Location property of each type (thanks Jorgen!)

Upvotes: 0

Jorgen Thelin
Jorgen Thelin

Reputation: 1076

In my experience, type mismatch problems like this are always caused by loading types from two different locations, even if you think they should be getting loaded from the same place.

Compare: Two Types not equal that should be

Try looking at the Assembly.Location property of each type in the debugger:

typeof(ISearchQueryManager).Assembly.Location
typeof(SlovenianSearchQueryManager).Assembly.Location

Upvotes: 10

Dan Bryant
Dan Bryant

Reputation: 27495

You may need to do this:

Register for this event somewhere in your application startup code (Program.cs is a good place):

    //Since we'll be dynamically loading assemblies at runtime, we need to add an appropriate resolution path
    //Otherwise weird things like failing to instantiate TypeConverters will happen
    AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;

And then handle it like this:

    private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        var domain = (AppDomain) sender;

        foreach (var assembly in domain.GetAssemblies())
        {
            if (assembly.FullName == args.Name)
                return assembly;
        }

        return null;
    }

My understanding is that this will make sure that a dynamically loaded assembly will resolve its dependencies using already loaded assemblies rather than loading a new copy of an already loaded assembly. This prevents the type of issues you've observed where the same Type is not valid because it's been loaded in the context of a different copy of the assembly.

Upvotes: 0

gbvb
gbvb

Reputation: 886

Can you try printing out the interfaces from the object created before casting it(Type.GetInterfaces() ).? that might give you an idea of what interfaces are exposed and you are getting what you think you are getting.. or using Activator.CreateInstance(String, String) variation and pass the Assembly name as well.

Upvotes: 0

Darin Dimitrov
Darin Dimitrov

Reputation: 1038830

One possible reason for this happening is that you have this ISearchQueryManager interface defined in two different assemblies which in fact doesn't represent the same type. I see that you are playing with dynamic assembly loading. So the interface you are statically casting to is not the interface implemented by the SlovenianSearchQueryManager class even if it has the same name.

Upvotes: 2

Related Questions