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?
Related
I have a solution that has a MVC-project and a windows console application. Both projects share the same Backend-Project, that loads and saves data.
I need to exchange the data from these two projects. Therefore I decided to use Isolated scope:
private string LoadInstallationFile()
{
IsolatedStorageFile isoStore = IsolatedStorageFile.GetMachineStoreForDomain();
if (!isoStore.FileExists(ClientSettingsFile)) return null;
/* do stuff */
}
private void SaveInstallationFile() {
IsolatedStorageFile isoStore = IsolatedStorageFile.GetMachineStoreForDomain();
using (IsolatedStorageFileStream isoStream = new IsolatedStorageFileStream(ClientSettingsFile, FileMode.CreateNew, isoStore))
{
using (StreamWriter writer = new StreamWriter(isoStream))
{
writer.WriteLine(data);
}
}
}
Now Inside the mvc-project I save the Data using "SaveInstallationFile()". I can access that file from within that mvc-project.
But when I try to access the data using the other (console-)project, the File does not exist.
How can I exchange data between these two?
(There is a big chance that both run under different user credentials, so GetUserStore...() IMHO would not work.
Both, the MVC-Application AND the Console-Application run on the Same Server.
If you really need to use isolated storage API you can use GetMachineStoreForAssembly (if this code is shared in the same assembly for both projects). Currently you use different storages for different applications. But to be honest, I would prefer to use database or custom configurable shared disk path as it looks more flexible solution.
GetMachineStoreForAssembly is less restrictive version of GetMachineStoreForDomain (both of them require code to be in the same assembly but GetMachineStoreForDomain requires it to be also in the same application). You can check MSDN documentation:
First method (GetMachineStoreForAssembly) is equivalent of GetStore(IsolatedStorageScope.Assembly |
IsolatedStorageScope.Machine, null, null)
Second method is equivalent of GetStore(IsolatedStorageScope.Assembly |
IsolatedStorageScope.Domain | IsolatedStorageScope.Machine,
null, null); (so, it includes one additional flag that's why it's more restrictive)
And also both of them check calling assembly. Not root executing assembly.
I have a windows form application written in C# that allows me to point to a folder of images and parse those images into a easily view able format for a user. This is a stand alone application and it works fine. I want to extend this application so that instead of it parsing a folder of images, I can hand it a prebuilt data set, with all of the images and meta data preset by an external application via an API.
I have been able to compile the application into a class library and access the classes and structs to actually build the data set without issue, the problem I am having now is launching the application externally with the data set I have built.
For context, I am writing a tool that will allow the user to call this windows form application from Spotfire. Inside of spotfire I am parsing a DataTable object and building the data set from the information I have. Once this data set is built I need to be able to launch the application as a stand-alone process instead of calling the forms explicitly inside of Spotfire. (This is due to a limitation of GUI threads in Spotfire and we can't call a multi threaded process in a single threaded application as well as we want to keep the Spotfire GUI responsive which can't be done if we call the forms directly)
I know I can launch the exe standalone using Process.Start(), however this doesn't let me pass my information to teh application. How can I build this application to allow me to pass information to it? I've been trying to google examples of how to do this and keep coming up empty handed as people will reference ASP.net or things that are over my head.
Thank you in advance!
EDIT: An example of an application that handles this really well is below. We use DPlot Jr to create graphs externally. The dplot.dll exposes the following function:
[System.Runtime.InteropServices.DllImport("dplotlib64.dll")]
public static extern int DPlot_Plot8(
ref DPLOT d, double[] x, double[] y, string cmds);
which I can then use in my code
docNum = dplot.DPlot_Plot8(ref dPlot, X, Y, cmds);
docNums.Add(docNum);
calling this function in this way actually launches the dplot application and passes the object I've built "dPlot" along with the X and Y data in order to plot the information. I would like to build something like this in my windows form application in order to be able to launch it easily from an external application. Unfortunately I don't know how this function works inside the .dll
EDIT2: I have been able to modify the runtime via the commandline as suggested by Aybe. In my desktop application I have created a conditonal in the main program like so.
if (args.Length == 0 && false)
{
Application.Run(new frmWaveFormViewer());
}
else
{
DataSet dataSet = new DataSet();
//dataSet.LoadMetaData(args[0]);
dataSet.LoadMetaData(#"C:\Users\a0273881\AppData\Local\Temp\tmp1141.tmp");
Application.Run(new frmWaveFormViewer(dataSet));
}
the user can then call the forms externally by using the following...
DataSet dataSet = new DataSet(dpList);
dataSet.PrintDatasetMetadataToFile(String.Format(#"C:\Spotfire\DataSetTesting_{0}.csv", DateTime.Now.ToString("yyyyMMdd_HHmmss")));
string args = dataSet.GetMetaData();
ProcessStartInfo starter = new ProcessStartInfo();
starter.FileName = #"C:\Users\a0273881\Desktop\WaveFormViewer.exe";
starter.Arguments = args;
Process.Start(starter);
However, this is not easy to use for other developers.
I am starting to look into WCF, can anyone provide good resources on WCF for dummies? I'm currently reading through: http://www.codemag.com/article/0705041
I have been able to spawn a NamedPipeServer on the application when it is launched. The named pipeserver names itself tagged with the name of the application + the process id that it spawns with. The process number is logged to a ini file in the users appdata folder. The process can be started with an optional command line argument to effect the value of the "callingApplication" which is the INI Header. This way, we can create multiple instances of the application from different callers without interfering and ensuring connection to the correct named pipe.
static void Main(string[] args)
{
string callingApplication = "None";
if (args.Length != 0)
{
callingApplication = args[0];
}
int pId = Process.GetCurrentProcess().Id;
PipeServer.StartPipeServer(pId, callingApplication);
// do things
PipeServer.StopPipeServer();
}
The PipeClient side is accessed through public functions available in a API static class. Functions that connect through the pipe are all housed in a seperate PipeClient class. These functions require a spawned process id in order to connect to the correct pipe. These are api functions to either launch or return the needed pipe from an api
public static class API
{
public static int SendCommand(int aKey, ...)
{
try
{
PipeClient.StartCommandSendClient(input, aKey);
}
catch (TimeoutException)
{
// returns error codes based on exceptions
}
return 0;
}
}
So with this I've managed to create a link between two applications. All that is really required past this is custom implementation of methods exposed through the API class which have custom client methods to call as well. All of this together is pretty simple to call from my calling app...
int aKey = API.GetKey("callingAppName");
API.SendCommand(aKey, "[Reset()][AddPoint(arg1, arg2, arg3)]");
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.
I use TextWriterTraceListener (System.Diagnostics) in my application to trace several things like exceptions,...
The application is running on a terminal server and if there are many users using it simultaneously the listener starts to create many tracefiles with random GUIDs in the filename.
Are there possibilities or workarounds to avoid this behaviour ?
I've just taken a look at the documentation for TextWriterTraceListener and there's a note about 1/3 of the way down the page
If an attempt is made to write to a file that is in use or unavailable, the file name is automatically prefixed by a GUID
So, this would appear to be by design. If the file is indeed unavailable then there's nothing that can be done about it with the current implementation. What you could try doing is writing a custom implementation of TextWriterTraceListener that overrides the relevant Write/WriteLine methods so that the output goes to a file, per user, with a name that better suits your needs.
If what you want is for ALL logging from ALL users on the Terminal Server to go to a single file, then you'll almost certainly need to have some kind of "3rd party" process running that "owns" the file and synchronises writes to it, such as a Windows Service that is then called by your custom TextWriterTraceListener
Was the fix calling the Trace.Listeners.Add(xxx listener) multiple times on accident?
Because if you have multiple listeners added they write too all listeners when you call the Trace.writeline();
Also local IIS might be continueing to have the file in use when you shut down the application.
I am currently testing the addition of System.Diagnostics.Trace.Listeners.Clear() in my output method...
// Upon a new day re-create the TextWriterTraceListener to update our file name...
if (_date?.Day != DateTime.Now.Day) { _listener = null; }
if (_listener == null)
{
System.Diagnostics.Trace.Listeners.Clear();
_fileName = $"{DateTime.Now.ToString("yyyy-MM-dd")}_Trace.json";
// Add a writer that appends to the trace.log file:
_listener = new System.Diagnostics.TextWriterTraceListener(_fileName);
_listener.IndentSize = 4;
_listener.TraceOutputOptions = System.Diagnostics.TraceOptions.None; // TraceOptions.DateTime | TraceOptions.ThreadId;
System.Diagnostics.Trace.AutoFlush = true;
System.Diagnostics.Trace.Listeners.Add(_listener);
// Obtain the Console's output stream, then add that as a listener...
System.Diagnostics.Trace.Listeners.Add(new System.Diagnostics.TextWriterTraceListener(Console.Out));
}
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."