Releasing a file that is loaded in Managed Extensibility Framework ( MEF ) - c#

I have ventured into the world of MEF for the first time and I am trying to figure out if it'll do what I am trying to accomplish. I am writing a windows service that is needed to call a few DLLs that are going to contain some business logic and then work with the datalayer. It was requested that these DLLs be "hotswappable" when the the windows service is running. I was hoping MEF can help me with this. I am attempting to test this out with a console application:
bool bFlag = true;
while(bFlag) {
DirectoryCatalog catalog;
CompositionContainer container;
catalog = new DirectoryCatalog(#"C:\serviceTest");
container = new CompositionContainer(catalog);
try {
var x = container.GetExport<IAlgorithm>();
var y = x.Value.Process("");
foreach(var z in y.Messages) {
Console.WriteLine(z.Message);
}
} catch(Exception ex) { Console.WriteLine("error"); }
container.ReleaseExports(container.GetExports<IAlgorithm>());
var o = Console.ReadLine();
if(o.Trim() != string.Empty) {
bFlag = false;
}
}
So now with that application running I drop the DLL that implements IAlgorithm into the folder and Process returns the messages I am using in the DLL. I then update that dll to return a different message and try to replace the previously used one, but I cannot. The file is locked by the application. Is there a way around this?
I've tried a few different ways to go about this code and my latest is trying container.ReleaseExports. I have tried disposing everything as well and get the same result. Am I doing something wrong, am I missing something, or is this simply not possible?

This seems like a duplicate post. Please take a look at this post. overwriting-dlls-in-mef
"This is not an MEF issue - it is your appdomain standard setup that locks the DLL's touched."

Related

Directory exists is producing inconsistant results on desktop vs server

I have a C# program which checks if a specific directory exists.
It is simply doing:
Directory.Exists(path).
I tried other ways as well. Using DirectoryInfo and using AlphaFS
On my local machine, the path exists. When I run the same program on a server with the same credentials it doesn't exist.
I wonder if it is a group policy issue. But I am able to go up one level and see it.
\server\volume\share\sub directory - Doesn't exist remotely but on my desktop it does
\server\volume\share - Does exist both on my desktop and remote server
Update
I forgot to mention, that since I had access to my desktop, I got the ACL information.
None of the groups were able to translate.
I really just want to get this application to behave the same way is on the server and find out why it is behaving differently.
Update 2
These are physical servers.
My desktop is Liquid VDI
Below is the code:
var path = txtPath.Text;
using (var user = new Impersonation(fuserdomain, fc_user, fc_pass))
{
var alphaExists = Alphaleonis.Win32.Filesystem.Directory.Exists(path);
var alphaDIExists = new Alphaleonis.Win32.Filesystem.DirectoryInfo(path).Exists;
var SystemExists = System.IO.Directory.Exists(path);
var SystemDIExists = new System.IO.DirectoryInfo(path).Exists;
var AlphaHasFiles = false;
var AlphaDIHasFiles = false;
var SystemHasFiles = false;
var SystemDIHasFiles = false;
try
{
Directory.GetFiles(path);
AlphaHasFiles = true;
}
catch { }
try
{
new DirectoryInfo(path).GetFiles();
AlphaDIHasFiles = true;
}
catch { }
try
{
System.IO.Directory.GetFiles(path);
SystemHasFiles = true;
}
catch { }
try
{
new System.IO.DirectoryInfo(path).GetFiles();
SystemDIHasFiles = true;
}
catch { }
MessageBox.Show(string.Format("alphaExists: {0}\nalphaDIExists: {1}\nSystemExists: {2}\nSystemDIExists: {3}\nAlphaGetFiles: {4}\nAlphaDIGetFiles: {5}\nSystemGetFiles: {6}\nSystemDIGetFiles: {7}\n", alphaExists, alphaDIExists, SystemExists, SystemDIExists, AlphaHasFiles, AlphaDIHasFiles, SystemHasFiles, SystemDIHasFiles));
}
Update 3
Although I have workaround this issue; I am still not sure why I would have a difference between my desktop and server. Is there any tool that can help me see where the issue may be?
I've seen the same thing with File.Exists. I never found an answer and finally threw in the towel, I simply try to use it and catch the exception.
Robust code has to catch it anyway, all the test does is avoid trying if the file or directory is not there. (And the PITA that Visual Studio no longer as any way to ignore an exception on a certain line. No problem runtime, annoying in development.)
This is a complete shot in the dark, since we don't have any specific details to go on. e.g. Is the server you're talking about physically yours, or is it a cloud-based server service?
I'd guess that your machine is an older operating system than the server, and the folder that you're trying to access is one of those special folders that has become more locked down with more recent operating systems (particularly on server operating systems) like the "Program Files" folder. So even though the folder exists on both, the method works on your machine but not on the server, due to permissions.
Hope this helps.
As far as I can tell, the Impersonation class in your code is not part of the dot net framework. Googling finds a couple of implementations. Where does it come from and How confident are you that it actually works in your scenario?
For example, if you remove the Impersonation code, and actually run it as that user, does that make it work?
One other clarification... When you say
\server\volume\share
Do you mean this is a network location (e.g. a UNC location), so is the same network path you are trying to access from both machines? If so, this would open up new possibilities for problems like firewalls, etc... Is that location on either of the two machines that we know about from the question, or a different location?

C# code or library to Update virtual directory contents without breaking clients

I have a lot of regularly updating static content that is made available via HTTP through IIS as a Virtual Directory. I have a C# application that updates this static content. The static content represents a matching set.
This content changes regularly and is validated before being made available to clients. I am currently doing a Directory Copy using this code but it is a bit brute force.
The content has a manifest file with version information. I know I can update the manifest file last but I don't want to pull the rug from under clients that are already downloading older content and leave them with a dirty set of files.
What is the recommended way to do a folder replace so that existing clients don't get a mixed up version of the file set? This must be common but I cannot find any libraries or best practice guidance to do this.
I've looked things like rsync for Windows and other backup/restore style tools but they all seem like overkill and generally don't have an API.
I ended up using the Microsoft Sync Framework. It worked out reasonably well. There are still a few bugs. Here's a good intro to the framework.
This is the significant part of my implementation.
public static bool DirectorySynchronisation(string sourceFiles, string targetFiles)
{
Trace.Info("Beginning Directory Sync");
try
{
Trace.Info("... between source location: {0} and targeted location: {1}", sourceFiles, targetFiles);
//Exclude metadata from sync.
var fileSyncScopeFilter = new FileSyncScopeFilter();
fileSyncScopeFilter.FileNameExcludes.Add("metadata.abc");
// Create file system provider
var source = new FileSyncProvider(Guid.NewGuid(), sourceFiles, fileSyncScopeFilter, FileSyncOptions.None);
var target = new FileSyncProvider(Guid.NewGuid(), targetFiles);
// Ask providers to detect changes
source.DetectChanges();
target.DetectChanges();
// Sync changes
SyncOrchestrator agent = new SyncOrchestrator
{
LocalProvider = source,
RemoteProvider = target,
Direction = SyncDirectionOrder.Upload //One way only
};
agent.Synchronize();
Trace.Info("Completed Directory Sync");
return true;
}
catch (Exception exception)
{
Trace.Info("Exception thrown while syncing files");
Trace.Exception(exception);
return false;
}
}
Hope this helps someone.

Difference between GetObject("", progId) and GetObject(, progId)

I'm trying to build an out-of-process COM server in C#. I've found this example from Microsoft: http://support.microsoft.com/kb/977996
I've build it and tested with a little VBScript:
Set app = GetObject("", "CSExeCOMServer.CSSimpleObject")
WScript.Echo(app.HelloWorld())
It works, but not when I do like this (skip the first argument of GetObject):
Set app = GetObject(, "CSExeCOMServer.CSSimpleObject")
WScript.Echo(app.HelloWorld())
I don't understand the difference between this two calls. I need the second form, because I want to make my calls from an environnement where only the second way is available.
What can I change to the server in order to make this works?
Ok, as often, I've found the solution by myself. In fact:
GetObject("", "CSExeCOMServer.CSSimpleObject")
is the same thing as:
CreateObject("CSExeCOMServer.CSSimpleObject")
If you were looking for a bad designed API, I've found one (but I don't know the whole story, may be someone here can explain me why it is like this).
The problem in my case is that the Microsoft sample doesn't register an object in the ROT (Running Object Table). So the GetObject call can not find an active object. I've resolved this by creating an instance of my class after adding this method to the constructor:
public void AddToROT()
{
IRunningObjectTable rot = null;
IMoniker moniker = null;
try
{
// Get the ROT
rot = GetRunningObjectTable(0);
// Create a moniker for the graph
moniker = CreateItemMoniker("!", "{" + CLASS_ID + "}");
// Registers the graph in the running object table
cookie = rot.Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, this, moniker);
}
finally
{
if (null != moniker) Marshal.FinalReleaseComObject(moniker);
if (null != rot) Marshal.FinalReleaseComObject(rot);
}
}

C# program connecting to example DBus daemon always gets 'Access is denied: DBus.BusObject'

For our current project we are using DBus (1.6.n).
It is largely accessed from C++ in shared memory mode, and this works really well.
I am now trying to access the same DBus from a C# program.
In order to try things out first, I downloaded the latest version of dbus-sharp I could find, and started the daemon included in the download to see if I could connect to it from my test C# app.
Whenever I make a connection, the daemon console shows that I am communicating with it, but as soon as I try to access any methods on the connection I get the error;
'Access is denied: DBus.BusObject'
Here is the code I have tried;
DBus.Bus dBus = null;
try
{
//input address comes from the UI and ends up as "tcp:host=localhost,port=12345";
//dBus = new Bus(InputAddress.Text + inputAddressExtension.Text);
//string s = dBus.GetId();
//dBus.Close();
//DBus.Bus bus = DBus.Bus.System;
//DBus.Bus bus = Bus.Open(InputAddress.Text + inputAddressExtension.Text);
//DBus.Bus bus = DBus.Bus.Session;
//DBus.Bus bus = DBus.Bus.Starter;
var conn = Connection.Open(InputAddress.Text + inputAddressExtension.Text);
var bus = conn.GetObject<Introspectable>(#"org.freedesktop.DBus.Introspectable", new ObjectPath("/org/freedesktop/DBus/Introspectable"));
bus.Introspect();
}
finally
{
if(dBus != null)
dBus.Close();
}
The commented code produces the same error eventually too.
I have stepped through with the debugger and it always gets to the following code in the TypeImplementer.cs;
public Type GetImplementation (Type declType)
{
Type retT;
lock (getImplLock)
if (map.TryGetValue (declType, out retT))
return retT;
string proxyName = declType.FullName + "Proxy";
Type parentType;
if (declType.IsInterface)
parentType = typeof (BusObject);
else
parentType = declType;
TypeBuilder typeB = modB.DefineType (proxyName, TypeAttributes.Class | TypeAttributes.Public, parentType);
if (declType.IsInterface)
Implement (typeB, declType);
foreach (Type iface in declType.GetInterfaces ())
Implement (typeB, iface);
retT = typeB.CreateType (); <======== Fails here ==========
lock (getImplLock)
map[declType] = retT;
return retT;
}
I have not found any useful examples or documentation about accessing DBus from C#, and there seem to be few recent entries about this anywhere, so maybe no-one else is trying this.
I am running the daemon in the same folder as the test program.
As I am running on windows, the daemon is listening on the tcp setting;
string addr = "tcp:host=localhost,port=12345";
Since this is the example included with the download, I thought it would be really simple to get it going, but alas no luck yet.
Has anyone else been here and know the next piece of the puzzle?
Any ideas would be appreciated.
Having received no comment or response, I will answer the question with the information I have found since asking it.
There appears to be no useful C# interface to DBus. (By useful, I mean one that works!)
The only information or examples I could find are not up to date and no effort appears to be being expended on providing a working interface.
I have decided to interface with DBus by using a C++ implementation written as a Windows service, and my C# program will send messages to DBus via the service. This seems to work ok, so satisfies the business need.
I am disappointed not to be able to get the C# to DBus working, but there are lots of service bus implementations that work on Windows, so in future I will look at implementing those instead of DBus.
If anyone does come up with a workable, documented solution to accessing DBus from C# on Windows, I would still be interested to see it.
I had the same error when I created new test project and add dbus cs source files to it main project assembly. It was when IBusProxy type dynamically created in dynamically created assembly.
asmB = AppDomain.CurrentDomain.DefineDynamicAssembly (new AssemblyName ("NDesk.DBus.Proxies"), canSave ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run);
modB = asmB.DefineDynamicModule ("NDesk.DBus.Proxies");
......
retT = typeB.CreateType ();
I think it was cause current running assembly isnt friendly for created assembly. And just when I add to project compiled NDesk.DBus.dll this error disappeared.

Programmatically set HTTP handlers in an ASP.NET application

I need to dynamically instantiate a web application from a console application. By this definition, I mean that my console application contains a web application that is not bound to IIS/XSP.
Currently, I create the web application into a temporary directory and copy some forged files into it. These are a special Global.asax that maps to my own implementation of HttpApplication to use in the web application (I need to do some initialization at app start), then I forge special .asmx files that map to my own skeleton classes and dynamic plugins
foreach (IPlugin plugin in _target.Plugins)
{
WsdlSkeletonDefinition[] defs = plugin.GetWsdlSkeletons();
if (defs != null)
foreach (WsdlSkeletonDefinition def in defs)
{
if (def.SkeletonType == null)
throw new LogbusException(string.Format("Plugin {0} declares empty skeleton type",
plugin.Name));
if (def.SkeletonType.IsAssignableFrom(typeof(System.Web.Services.WebService)))
throw new LogbusException(
string.Format("Plugin {0} does not declare a valid WSDL skeleton type", plugin.Name));
string fname = def.UrlFileName;
if (fname.EndsWith(".asmx", false, CultureInfo.InvariantCulture))
fname = fname.Substring(0, fname.Length - 5);
if (!Regex.IsMatch(fname, #"^[a-zA-Z0-9_\.\-%]+$", RegexOptions.CultureInvariant))
throw new LogbusException(string.Format(
"Plugin {0} declares invalid WSDL endpoint: {1}",
plugin.Name, def.UrlFileName));
string wsDeclaration = string.Format(ASMX_TEMPLATE, def.SkeletonType.AssemblyQualifiedName);
using (
StreamWriter sw = new StreamWriter(File.Create(Path.Combine(_physicalPath, fname + ".asmx")),
Encoding.Default))
sw.Write(wsDeclaration);
//Copy skeleton asembly if needed
CopyAssemblyTo(def.SkeletonType.Assembly, bindir);
foreach (AssemblyName dependency in def.SkeletonType.Assembly.GetReferencedAssemblies())
{
try
{
CopyAssemblyTo(Assembly.Load(dependency), bindir);
}
//Possible broken dependency
catch { }
}
}
}
My approach works, but I'm not so satisfied by it because I have to write lots of garbage into file system, even if I eventually delete it all.
I know I can control HTTP handlers via Web.config, but I don't want to forge a Web.config for that. I would like to create a mapping such as I can remove the .asmx extension from web services' URLs and still get them.
For example, one of the default scripts is "LogbusManagement.asmx", which must be hard-coded into client APIs and the .asmx prevents portability to other platforms such as PHP. I want to make "LogbusManagement.asmx" equivalent to "LogbusManagement" and any extension. For this, I might use an HttpHandlerFactory.
My straight question is,
like asked here by somebody else: is there a way to programmatically, possibly from Global.asax, to set IHttpHandlers or IHttpHandlerFactories for web applications?
Thank you
This question was already answered in the stackoverflow:
Any way to add HttpHandler programatically in .NET?

Categories