Getting Information about a assembly which is present in Solution - reflection

Scenario: I want to load a assembly at run time which is present in Solution.
The belo code will not work as it is not present in Cuurent App Domain.
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
Also if i will search in referenced assemblies, then also it can not be found as it is not referenced. So the below code will also not work:
public static IEnumerable<Assembly> GetAssemblies()
{
var list = new List<string>();
var stack = new Stack<Assembly>();
stack.Push(Assembly.GetEntryAssembly());
do
{
var asm = stack.Pop();
yield return asm;
foreach (var reference in asm.GetReferencedAssemblies())
if (!list.Contains(reference.FullName))
{
stack.Push(Assembly.Load(reference));
list.Add(reference.FullName);
}
}
while (stack.Count > 0);
}
Do you guyz have some suggestion ?

Sign your assembly, then in your app.config, specify the fully qualified assembly name. Call Assembly.Load(string), passing the assembly name from your app.config.
NOTE: The assembly you are attempting to load must be in a location where the runtime can find it. Your best bet is either to put it into the Global Assembly Cache, or make sure it is in the same folder as your executing assembly.

Related

Could not load file or assembly

I want to archive a pdf version of a DESADV, therefore I create a Html page via Biztalk Custom XSLT Mapping from the original XML file and render it via Pechkin.Synchronized to a pdf (wrapper for wkhtmltopdf).
This works like a charm in my Solution, but once I try to deploy the solution to the QA System biztalk keeps nagging that it can not find the Pechkin Library.
The Libs are deployed via "gacutil -I", I even build it from source and signed it with our Biztalk signing key and changed the build mode from x86 to "any CPU".
I added all the needed dlls to the Helper Class and deployed them also manually but BizTalk is unable to access the lib. Please help me, I am trying for days without making any progress and it makes me mad.
I even struggle to debug why it can not load the dll.
I am not so fluent in BizTalk and always thought that DLLs in the GAC are accessible to BizTalk...
I also build a console application, that directly references to the DLL in GAC_MSIL and the application renders the html with the exact code, I wrote in the BizTalk Solutions helper class.
even this can not be considered a real answer but it solved the problem somehow.
As already someone mentioned it, the DLL had dependencies onto other libs. This in combination that I was unable to deploy the DLL to the gac and no deeper understanding of the topic I simply chose another lib as this already took to much time. meh.
I choose the shareware https://selectpdf.com/community-edition/, they have a nuget package that simply worked. (i like). The overall render speed is not as good, but in the end it is more important to stay BizTalk compatible with your project I guess.
If someone stumbles upon this:
Create XSL Mapping for your Message XML and map it to some fancy
HTML layout (css supported)
Xtract XML from BizTalk Message in Orchestration
Render PDF with a Helper Solution
My code of the helper class:
You need to add the "Microsoft.XLANGs.BaseTypes" reference from References->Add reference->Assemblies->Extensions for it to work.
using System;
using Microsoft.XLANGs.BaseTypes;
using System.IO;
namespace BIS.CLC.DESADV.Helper
{
public class HtmlHelper
{
public string xTractStringFromMessage(XLANGMessage message)
{
string retVal = string.Empty;
try
{
using (var reader = new StreamReader(message[0].RetrieveAs(typeof(Stream)) as Stream))
{
retVal = reader.ReadToEnd();
}
}
catch (Exception ex)
{
Exception logex = new Exception("BIS.CLC.DESADV.Helper.HtmlHelper.xtractStringFromMsg: string extraction failed" + ex.Message.ToString() + ex.InnerException.ToString());
BIS.Common.Helper.StaticClass.writeEventLog_BizTalk(logex.Message.ToString(), "BisLog");
throw ex;
}
finally
{
message.Dispose();
}
return retVal;
}
public void renderPDFfromHTML(string html, string targetPath)
{
try
{
//do things
SelectPdf.HtmlToPdf converter = new SelectPdf.HtmlToPdf();
SelectPdf.PdfDocument doc = converter.ConvertHtmlString(html);
doc.Save(new Uri(targetPath).LocalPath.Replace(".XML", ".PDF"));
doc.Close();
}
catch (Exception ex)
{
Exception logex = new Exception("BIS.CLC.DESADV.Helper.HtmlHelper.renderPDFfromHTML: render pdf failed " + ex.Message.ToString() + ex.InnerException.ToString());
BIS.Common.Helper.StaticClass.writeEventLog_BizTalk(logex.Message.ToString(), "BisLog");
throw ex;
}
}
}
}

Workflow Foundation 4 Imports panel not refreshed

I would like to import a new reference into my Workflow Designer, however I encounter a weird problem.
Here's my code to import a reference.
var root = GetRootElement();
VisualBasicSettings vbs = VisualBasic.GetSettings(root);
vbs.ImportReferences.Add(new VisualBasicImportReference { Assembly = Assembly.Load("Castle.Core").FullName, Import = "Castle.Core.Configuration.Xml" });
private object GetRootElement()
{
var modelservice = workflowDesigner.Context.Services.GetService<ModelService>();
if (modelservice == null)
return null;
var rootmodel = modelservice.Root.GetCurrentValue();
return rootmodel;
}
It works when I load my designer for the first time, the assembly is well added into the hashset ImportReferences then I also see the namespace in the "Imports" panel. But when I call the above method when user picks a dll through a picker dialog, I call the code above, the assembly is also well added to ImportReferences, but the "Imports" panel is not refreshed...
Any ideas ?
Thanks for your help.
Have you tried DesignerView.OnReferenceUpdated? It seems what you're looking for:
If the referenced assembly is added, the namespaces of the types found
in the assembly are added to the list of imported namespaces. If the
referenced assembly is removed, the namespaces of the types found in
the assembly are removed from the list of imported namespaces.
Usage example:
var designerView = workflowDesigner.Context.Services.GetService<DesignerView>();
designerView.OnReferenceUpdated(assemblyName, true/false);
Actually, the namespace is well imported, it was hided in the dropdownlist above.
Here's the most simple code to import a namespace.
http://blogs.msdn.com/b/tilovell/archive/2011/11/02/wf4-adding-vb-namespace-imports-to-your-workflow-programmatically.aspx

Read AssemblyTitle attribute in ASP.NET

I use code below to read AssemblyTitle attribute of .NET apps, unfortunately Assembly.GetEntryAssembly() always return Null in ASP.NET app. How to read AssemblyTitle in ASP.NET app?
public static string Title
{
get
{
var attributes = Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false);
if (attributes.Length > 0)
{
var titleAttribute = (AssemblyTitleAttribute)attributes[0];
if (titleAttribute.Title.Length > 0)
return titleAttribute.Title;
}
return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().CodeBase);
}
}
You must have a type that you know is defined in the same assembly that contains the AssemblyTitle. Then you can do:
typeof(MyType).Assembly.GetCustomAttributes
Note that (for what I know) there isn't any other bulletproof method.
For example using HttpContext.Current doesn't work if you want to do it not during a web request (so you can do it on response of a user action, but not from a separate thread, or from a static initializer, or from global.asax)
Some similar readings (full of half successes):
GetEntryAssembly for web applications
Using the Web Application version number from an assembly (ASP.NET/C#)
I use the following in asp.net web app:
if (ApplicationDeployment.IsNetworkDeployed)
return ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString();
return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
Edit: Sorry, thats just the version, not the title! I combined your version and mine:
System.Reflection.Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false);
That gets the assembly title attribute just fine. The difference is in GetExecutingAssembly() versus your GetEntryAssembly().

Why would System.Type.GetType("Xyz") return null if typeof(Xyz) exists?

I have come across a strange behaviour in my (huge) .NET 4 project. At some point in the code, I am referring to a fully qualified type, say:
System.Type type = typeof (Foo.Bar.Xyz);
later on, I do this:
System.Type type = System.Type.GetType ("Foo.Bar.Xyz");
and I get back null. I cannot make sense of why this is happening, because my type name is correct, and I have checked with other types and they get resolved properly. Moreover, the following LINQ query finds the type:
var types = from assembly in System.AppDomain.CurrentDomain.GetAssemblies ()
from assemblyType in assembly.GetTypes ()
where assemblyType.FullName == typeName
select assemblyType;
System.Type type = types.FirstOrDefault ();
Are there any reasons why System.Type.GetType could fail?
I have finally had to resort to this piece of code instead of GetType:
System.Type MyGetType(string typeName)
{
System.Type type = System.Type.GetType (typeName);
if (type == null)
{
var types = from assembly in System.AppDomain.CurrentDomain.GetAssemblies ()
from assemblyType in assembly.GetTypes ()
where assemblyType.FullName == typeName
select assemblyType;
type = types.FirstOrDefault ();
}
return type;
}
If you just give a class name (which does need to be fully-qualified in terms of the namespace, of course) Type.GetType(string) will only look in the currently executing assembly and mscorlib. If you want to get types from any other assembly, you need to specify the absolutely full name including the assembly information. As François says, Type.AssemblyQualifiedName is a good way of seeing this. Here's an example:
using System;
using System.Windows.Forms;
class Test
{
static void Main()
{
string name = typeof(Form).AssemblyQualifiedName;
Console.WriteLine(name);
Type type = Type.GetType(name);
Console.WriteLine(type);
}
}
Output:
System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
System.Windows.Forms.Form
Note that if you're using a strongly named assembly (like Form in this case) you must include all the assembly information - versioning, public key token etc.
If you're using a non-strongly-named assembly, it's easier - something like:
Foo.Bar.Baz, MyCompany.MyAssembly
for a type called Baz in namespace Foo.Bar, in assembly MyCompany.MyAssembly. Note the absence of ".dll" at the end - that's part of the filename, but not the assembly name.
You should also be aware of the differences between C# names and CLR names for things like nested classes and generics. For example, typeof(List<>.Enumerator) has a name of System.Collections.Generic.List`1+Enumerator[T]. The generics side is tricky to work out, but the nested type bit is easy - it's just represented with a "+" instead of the "." you'd use in C#.
As far as I know GetType looks for "Xyz" in an assembly named Foo.Bar.dll and I'm assuming it doesn't exist.
GetType relies on your passing the exact path to Xyz in the assembly.
Assembly and namespace don't have to be related.
Try System.Type type = System.Type.GetType(typeof(Foo.Bar.Xyz).AssemblyQualifiedName) and see if that works.
The reason you find it with your LINQ example is that you are using GetAssemblies which obtains the assemblies that have been loaded into the current execution context and thus has the details it needs to find all the types within the assemblies.
From the MSDN documentation (my emphasis):
If typeName includes the namespace but not the assembly name, this method searches only the calling object's assembly and Mscorlib.dll, in that order. If typeName is fully qualified with the partial or complete assembly name, this method searches in the specified assembly. If the assembly has a strong name, a complete assembly name is required.
I just stumbled upon a similar problem and want to leave this here
First of all your can specify the AssemblyName in the string
var type = System.Type.GetType("Foo.Bar.Xyz, Assembly.Name");
However this only works for assemblies without a strong name. The explaination is already in Simons answer If the assembly has a strong name, a complete assembly name is required.
My problem was I had to resolve a System.Dictionary<?,?> from a string at runtime. For a Dictionary<int, string> this might be easy but what about a Dictionary<int, Image>?
this would result in
var typeName = "System.Collections.Generic.Dictionary`2[System.Int32, [System.Drawing.Image, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a]]";
But I don't want to write the strong name. Especially because I don't want to include the versions since I am planning to target multiple frameworks with my code.
So here is my solution
privat statice void Main()
{
var typeName = "System.Collections.Generic.Dictionary`2[System.Int32, [System.Drawing.Image, System.Drawing]]";
var type = Type.GetType(typeName, ResolveAssembly, ResolveType);
}
private static Assembly ResolveAssembly(AssemblyName assemblyName)
{
if (assemblyName.Name.Equals(assemblyName.FullName))
return Assembly.LoadWithPartialName(assemblyName.Name);
return Assembly.Load(assemblyName);
}
private static Type ResolveType(Assembly assembly, string typeName, bool ignoreCase)
{
return assembly != null
? assembly.GetType(typeName, false, ignoreCase)
: Type.GetType(typeName, false, ignoreCase);
}
Type.GetType(...) has an overload which acceps a func for assembly and type resolving which in neat. Assembly.LoadWithPartialName is deprecated but if it's dropped in the future I could think of an replacement (iterate all assemblies in the current AppDomain and compare the partial names).

how to use asp.net dynamic data with Entity framework in another dll

how can i use asp.net dynamic data using EF in another dll and i dont want to put connection string in web.config or any config file.
I have this code in Global.asax
model.RegisterContext(() => new MyObjectContext("entityconnectionString"), new ContextConfiguration() { ScaffoldAllTables = true });
the defalut page is ok but when i click on any table to see the details, I get this error:
The specified named connection is either not found in the configuration, not intended to be used with the EntityClient provider, or not valid.
How can i solve this problem?
I was able to resolve this by forcing the load of the MetadataWorkspace and use an overload of the RegisterContext().
var context = new MyEntities(); // DataContext
context.MetadataWorkspace.LoadFromAssembly(typeof(MyEntity).Assembly); // An EF Entity
var config = new ContextConfiguration() {ScaffoldAllTables = true};
DefaultModel.RegisterContext(() => context, config);
I'm having the same problem. I have my EDMX data model file in one project called NW.DataModel. I added the code generation item for POCO objects, which I then moved off to a separate project called NW.Entities, so that they could be persistence ignorant. I have to tweak a few property settings for namespace generation in the Context object so that the Context would recognize the entities when building the solution. This was all fine, and I can use these projects in Console apps and a WCFdata service. Now I want to add a dynamic data site for some basic admin, and that's when the separate assemblies no longer play together. I'm just testing the project settings with the Northwind database.
I get this error: Could not find the CLR type for 'NWEntities.Shipper'.
This blog post seems to have some ideas, and links to forums where the issue has some recent activity, but no word from Microsoft yet.
http://thedatafarm.com/blog/data-access/wcf-data-services-and-ef-pocos-that-are-in-their-own-assembly/
Jeff's answer just about works for me, but I kept getting ObjectDisposed Exceptions every now and then.
I've changed the context factory to create a new context, which seems to work:
var config = new ContextConfiguration() { ScaffoldAllTables = true };
DefaultModel.RegisterContext(() =>
{
var context = new MyEntities(); // ObjectContext
context.MetadataWorkspace.LoadFromAssembly(typeof(AnyPOCOInOtherAssembly).Assembly);
return context;
},
config);

Resources