Jump to content
Sign in to follow this  
boen_robot

Dynamic assembly

Recommended Posts

I have a C# applicaiton which compiles and runes fine.... but... on my computer only and with an assembly reffered to prior to compilation.I'd like to let the user specify the assembly's location, and use that one from within my app.If I have to be more concrete, I have a wrapper around SAXON, but I'd like to let the user use their version of SAXON (not mine), and use it regardless of its location.How can I do something like that?I use Microsoft Visual Studio 2005 Professional.My current source code (or should I say "what's significant of it") is:

using javax.xml.transform;using java.lang;using net.sf.saxon;using net.sf.saxon.trans;using net.sf.saxon.@event;using System.Collections;namespace xslt2processor{	class saxon : Transform	{		static void Main(string[] args)		{			//to be removed in the final version			string source = "D:\\test.xml";			string stylesheet = "D:\\test.xsl";			(new saxon()).scan(new string[] {source, stylesheet});			//For debugging only			System.Console.Read();		}		void scan(string[] args)		{			base.doTransform(args, "");		}		public override void setFactoryConfiguration(bool schemaAware, string arg1)		{			if (schemaAware) {				this.config = Configuration.makeSchemaAwareConfiguration(null, "");			} else {				this.config = new Configuration();				this.config.setAllNodesUntyped(true);			}			this.config.setErrorListener(new MyListener());			//this.config.setMessageEmitterClass("xslt2processor.MyMessage");			this.factory = new TransformerFactoryImpl(config);		}	}	class MyListener : ErrorListener	{		//Implementation of my ErrorListener	}	class MyMessage : Receiver	{		//Implementation of my message receiver	}

Oh, and, if the line '//this.config.setMessageEmitterClass("xslt2processor.MyMessage");' is uncommented, I get a runtime error that MyMessage could not be loaded, but that's another story I'll be sorting out later.[edit]OK, I saw the System.Reflection class from this article, which seems to hold the key functions to load an assembly at run-time... but how would I ever fit THAT into my current implementation?[/edit]

Share this post


Link to post
Share on other sites

I have never seen anything like this attempted before. I can't imagine there being a [reliable] way to do this. Let's say we can get this working, 2 years from now when there are newer versions of SAXON you have noway of knowing if it will be compatible. If SAXON simply changes a method name or return typoe your whole app breaks!I would recommend just including your SAXON assembly with your app, it will save you time and it will gaurantee it will always work.

Share this post


Link to post
Share on other sites
I have never seen anything like this attempted before. I can't imagine there being a [reliable] way to do this. Let's say we can get this working, 2 years from now when there are newer versions of SAXON you have noway of knowing if it will be compatible. If SAXON simply changes a method name or return typoe your whole app breaks!I would recommend just including your SAXON assembly with your app, it will save you time and it will gaurantee it will always work.
I am really hoping that two years from now, there will be an XSLT 2.0 processor written in C, and a corresponsing PHP extension, and so this thing won't be needed.In the meantime, I have a wrapper that already allows PHP to execute SAXON. But the problem is error messages and xsl:message outputs. SAXON outputs everything into the CLI in its own text format. It's almost impossible to get a proper error message delivered to PHP.So, as the author of SAXON - M.Kay - suggested, I decided to write this wrapper with the idea to format the error messages to my liking, from which point on, delivering them to PHP is a breeze. It's already working great in JAVA. Its .NET's turn.If SAXON does change a method name (or something) in the forseeable future, then I'll add an argument to my app's command line to ask for the version, and act based on that. I already do that on the PHP level, so passing it to the .NET level won't be a big bother.I'd still like to let the user keep current with as most recent version of SAXON as possible. It sounds silly for me to update my release just because a new maintainance release of SAXON was released.

Share this post


Link to post
Share on other sites

After seeing the Reflection namespace, I was thinking more of Assembly.LoadFile() since I won't require for SAXON to be a registered assembly (i.e. the DLL can be anywhere).But still, how could I translate what I have now to something that would use that function? I mean, I actually have to not just execute some stuff from an assembly. I actually have to override a class from an assembly, and execute my subclass. That's really the part that bothers me most.

Share this post


Link to post
Share on other sites

I did find this. In .Net an assembly must be registered before it can be used. By default, all assemblies in the bin folder are registered. In order to register an assembly that is outside the bin folder you have 2 options otulined in this article http://support.microsoft.com/kb/837908

Share this post


Link to post
Share on other sites
I did find this. In .Net an assembly must be registered before it can be used. By default, all assemblies in the bin folder are registered. In order to register an assembly that is outside the bin folder you have 2 options otulined in this article http://support.microsoft.com/kb/837908
Thanks. The last option is, I think, my best bet. But when trying it out, I got a run time uncaught System.IO.FileNotFoundException saying the assembly couldn't be loaded.
using javax.xml.transform;using java.lang;using net.sf.saxon;using net.sf.saxon.trans;using net.sf.saxon.@event;using System.Collections;using System.Reflection;using System;namespace xslt2processor{	class xslt2processor	{		static Assembly assemblyResolver(object sender, ResolveEventArgs args)		{			System.Console.Error.WriteLine(sender.ToString() + ";" + args.ToString());			return Assembly.LoadFile("D:\\vasko\\Software\\XSLT2\\saxonb8-9-0-4n\\bin\\saxon8.dll");		}		static void Main(string[] args)		{			try			{			AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(assemblyResolver);			string source = "D:\\test.xml";			string stylesheet = "D:\\test.xsl";							(new saxon()).scan(new string[] { source, stylesheet });			}			catch (System.Exception e)			{				System.Console.Error.WriteLine("Exception raised: " + e.ToString());			}			System.Console.Read();		}	}	class saxon : Transform	{		public void scan(string[] args)		{			base.doTransform(args, "");		}	//Same code	}	//Same code

Now, I know for sure the assembly exists at this locaiton, so what could be the problem?

Share this post


Link to post
Share on other sites

Nope. Same deal. I assume I'm not subscribing to the AssemblyResolve event correctly, but after all, I need to know how it really works (which is why I output its arguments on the error stream. I was hoping to find my way from there).The exact message, in both cases is:

Unhandled Exception: System.IO.FileNotFoundException: Could not load file or ######embly 'saxon8, Version=8.9.0.4, Culture=neutral, PublicKeyToken=e1fdd002d5083fe6' or one of its dependencies. The system cannot find the file specified.File name: 'saxon8, Version=8.9.0.4, Culture=neutral, PublicKeyToken=e1fdd002d5083fe6' at xslt2processor.xslt2processor.Main(String[] args)WRN: Assembly binding logging is turned OFF.To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.Note: There is some performance penalty associated with assembly bind failure logging.To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].
(plus an ugly error window appearing with "Close" and "Debug" buttons)At least... where is the exception coming from? I wanted to at least catch it, debug from there. It says xslt2processor.xslt2processor.Main, but all of this area is in a "try" block.

Share this post


Link to post
Share on other sites

Try breaking it into more try blocks or commenting the code out and then uncommenting one line at a time to find the exact cause of the error.

Share this post


Link to post
Share on other sites

You might also try adding something like this to your assembly loading function:

static Assembly assemblyResolver(object sender, ResolveEventArgs args){	System.Console.Error.WriteLine(sender.ToString() + ";" + args.ToString());	string path = "D:\\vasko\\Software\\XSLT2\\saxonb8-9-0-4n\\bin\\saxon8.dll";	if(System.IO.File.Exists(path) == false)	{		throw new System.IO.FileNotFoundException("Could not find the DLL at '" + path + "'");	}	return Assembly.LoadFile(path);}

If that new FileNotFoundException occurs, then, most likely, you are either pointing the code to the wrong location or that file/directory will not allow your code to access it with its current permission settings.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

×
×
  • Create New...