Hold COM-reference in .net web service - web-services

I have tried to make a webservice interface to a state-holding COM component.
The webservice basically contains operations Start, Shutdown and GetCurrentState.
Start creates a COM component, Stop releases.
And GetCurrentState retrieves information from the COM component.
It seemed an easy thing, but after a day it still refuses to work.
I have tried storing the COM-reference as a member variable in the C# object. The object is constantly re-created.
Then I tried to store the COM-reference in the Session object. But still, something is still wrong.
Anyone know how one should store COM reference which should stay alive inside webservices?
/L

Assuming you are using ASMX here, and not WCF where you could control the life time little bit differently, each time a request comes in the class that services the request is recreated. This is the standard behaviour for ASMX.
What you need to do is store the COM object either inside the Cache[] or Application[] collections. It may still get destroyed when the worker pool is recycled. Some code like this is what you need:
public FooClass GetFooClassInstance()
{
FooClass instance = (FooClass)this.Context.Application["FooClassInstance"];
if (instance == null)
{
instance = new FooClass(); // Creates the RCW.
this.Context.Application["FooClassInstance"] = instance;
}
return instance;
}
The FooClass is the runtime callable wrapper for your COM object. The Application object contents is retained between requests. One thing you do need to watch out for is the threading model that the COM component is using as some can cause performance problems because they marshal calls onto a single thread.

Web service by its nature is stateless. Try creating Windows service and using Web service to control it. Start method would start Windows service and that service would instantiate COM-component. GetCurrentState method would communicate with the service and grab COM reference.
Another approach is to make your COM component COM+ accessible:
Open Administrative Tools -> Component Services.
Open COM+ Applications node.
Create new application. Select "Create an empty application" in the first wizard step. Type application name and select "Server application" option in the next step.
Create new component. Select "Install new component(s)" in the wizard. Locate and select your COM dll.
Go to component properties and enable object pooling. Set minimum and maximum pool size to 1. This will make your component a singleton.

Related

How does an addin get a reference to the host?

I am experimenting with the System.Addin MAF capability. I have a host that creates an instance of a new addin in a new appdomain and starts it running.
I'd like to have the addin call methods on the host to pass data back up. It is clear how to have the host create an instance of the addin (AddinToken.Activate), but how does the addin get a reference to the host?
I have tried passing a copy of the host down to the addin through an Initialise method, but because it needs to be serializable, this causes difficulties. I have to mark some properties as NonSerialized which mean they are null when the addin calls the methods on it. I get the feeling that although there is a View & Adapter written to support the Addin->Host contract, it is being bypassed by this method?
You don't pass a copy of the host down to the addin. Rather you need to define an interface that you pass to the addin and provide an implementation on the host side.
For example, you could define an Initialize method that the AddIn has to implement. You could specify parameters to that method that represent services provided by the host. One case where I use this is to provide a logging interface to the addin. The initialize method is defined as:
void Initialize(ILogger logger);
When the host calls initialize on the AddIn, it passes an implementation of ILogger that the Addin can then hold onto and call whenever it needs to log.

Only aysnc methods lsited when call wcf

I am trying to call a WCFService from Windows phone 8 which connects and returns data fine when i use WCFTestClient but when I refreence the service using add reference and then try to access in code only the async methods are showing in intelesence. I have not delciared my methods as aync how can i ensure I can access my other methods as I calling a webservice does it need be aysnc.
// Constructor
public MainPage()
{
InitializeComponent();
// Sample code to localize the ApplicationBar
//BuildLocalizedApplicationBar();
IcuroServiceClient _db = new IcuroServiceClient();
var json =_db.GetPersonByIdAsync(1);
}
And if so How would I convert a method that is as simple as below to Aysnc ?. I am used to asmx services and new to WCF.
public string GetListByUserId(string userId)
{
List<curoList> myList = _db.GetAllListsByUserId(userId);
var json = JsonConvert.SerializeObject(myList, Newtonsoft.Json.Formatting.None);
return json;
}
Its grayed out here for me mate In my normal signature im returning a string but the asyncs dont look like their returning anything just void .
Windows phone is based literally and figuratively on the Silverlight motif of keeping all service calls async only. It is a two step process where one has to think backwards. Here are the steps
Provide a callback method whose job it is to handle the resulting data or error in an appropriate fashion.
Then make the call as one normally would (but calling the async version) to start the process off on a separate thread.
Be cognizant of not directly loading to the GUI in the callback method for the result is on a different thread; note that loading to VM properties is fine for the most part whereas the update to any GUI subscribed bindings will be done on the thread.
Hot to Resolve
In the example given before the call to to db.GetPersonByIdAsync(1) provide (find using intellisense) the async subscription method that has the call back.
It may be prefixed with either a Load method or a Begin call, for the PersonById.
In the editor, the providing of a method is usually done by intellisense which where one can tab an example into code. That is so one doesn't have to root out the parameters for the callback method.
Possible example, shows the how to do it:
client.GetPersonByIdAsyncCompleted += MyMethodToHandleResultforGetPerson; // var personId = e.Result;
client.GetPersonByIdAsync(1);
Why
When Silverlight was designed, having a program wait (even if its busy waiting) on any thread would slow down the browser experience. By requiring all database (service) calls to be asynchronous ensures that the developer can't slow down the browser, in particular by bad code. Loosely speaking that motif carried over to the windows phone where Silverlight was brought over as the main operations for the phone.
It took me awhile to get used to the process, but now that I have worked on Silverlight and Windows phone, I actually use the async motif in WPF even though I don't necessarily have too, it makes sense in terms of data processing and thread management.
It is not easier for the developer per-se for everyone learns in a synchronous hello world, but it is adapted for the needs of the target platform and once learned it becomes second nature.

COm server accessing the application

I have written a simple dialog based MFC application using a thirdd party soft tree control. I am trying to write a automation client for the application. For this I wrote a singleton out-of-process COM Testing Agent for the dialog based application sample app. The Com server exposes a Run method to the automation client. This Run method access the gut of the mfc app and actually mimicks a click on the GUI. The problem i am facing is when the automation client tries to invoke Run method on the Com object it is able to invioke it but when the Run method crashes when it tries to access the control's methods such as getCaretInedx.
I have tried to cach the exception and log the message to a file but have not been able to do so.
My question is: Is there any limitation in the way a com object can access the application? Or am i missing anything to facilitate this.
Any help or pointer is greatly appreciated. Since this is my first in COM I have not been able to make much progress.
Thanks
Is your client's window actually being created? If not, the hwnd doesn't exist, which is probably why it crashes. Furthermore, your client may be hidden behind another window when it is started, and may exhibit different behavior than when the user called it through regular interaction.
In general, calling code that relies on or interacts with the UI from a COM server is fraught with peril, especially when that code is not written in the first place to behave like this. Most UI isn't that defensive about HWND's existing etc.

Getting a pointer to an existing COM object?

How do you get a pointer to an existing COM object that has been created on the same machine, in a different process?
I have a Credential Provider which creates an object that inherits ICredentialProvider. ICredentialProvider has a method SetSerialization.
I also have a service, from which I need to call the SetSerialization method of the Credential Provider. The thing is, I'm experienced in C++, but I'm a beginner with COM, so I don't know how. Microsoft's sample 'CSampleProvider's comments say to call the SetSerialization method from a 'remote client', but don't explain how - I assume they assume you know COM.
I've been reading MSDN and various tutorials about COM all day, and I've got to a point where I can create an instance of my Credential Provider in the service, but I need to get a pointer to the Credential Provider object that already exists, not create a new one, and I can't find out how.
How is it done?
Thanks.
The canonical method is via the Running Object Table. That assumes the object has a "moniker", i.e. a COM name, and that this moniker is registered.
Note that the ROT is a form of IPC, specifically a systemwide directory of COM objects.
As Raymond said, in short, you can't - not by any built in COM functionality at least. If you must, it will need to be passed via some form of Inter Process Communication.

How should I store an object in an asp.net web service so that business objects can reference the object?

I am building an ASP.NET web service that will be used internally in my company. Exception and trace/audit logging will be performed by the web service class as well as the business objects that the web service will call. The logging is handled by an instance of an internally developed log helper class. The log helper must be an instance as it tracks state and a reference guid that is used to relate the log messages into groups.
In the past we handled this situation by passing references to the log helper instance from class to class using the method parameters. I am trying to find a reliable way to find a way to store and access the instance throughout the call without having to explicitly pass it around.
I am attempting to store the instance in the HTTPContext during the early stages of the web service call. When my business objects need it later during the call, they will access it as a property of a base class that all my objects inherit from.
Initially I tried storing the instance in the web service's Context.Cache. This seemed to work and my research led me to believe that the Cache would be thread safe. It wasn't until I started calling the web service from more than 3 concurrent sessions that the instance of the logger would be shared from call to call rather than be recreated new for each call. I tried Context.Application and found very similar results to the Cache storage.
I was able to find what looks like a usable solution with Context.Session. This requires me to use EnableSession = true in the attributes of each method but it does seem to keep the instance unique per call. I do not have a need to track data between calls so I am not storing session cookies in the client space.
Is session the optimal storage point for my needs? It seems a little heavy given that I don't need to track session between calls. I'm open to suggestions or criticism. I'm sure someone will suggest using the built in Trace logging or systems like Elmah. Those might be an option for the future but right now I don't have the time required to go down that path.
Update: I should clarify that this service will need to run on .Net Framework 2.0. We are in the process of moving to 3.5/4.0 but our current production server is Win2000 with a max of 2.0.
You could try using OperationContext.Current. This will enable you to store variables for the lifetime of the web service call.
Edited to ad a possible No WCF Solution:
Since you don't have WCF, you can create something like thread local storage by creating a static map of thread IDs to your object. Just make sure that you are correctly cleaning up this static map when requests are finished or else the next call that uses that thread will pick up your object. Also, make sure to lock the map when you are accessing it.
I take it that, in the past, you have used these business objects in a Windows Forms application?
You should not have your business objects dependent on some ambient object. Instead, you should use either constructor injection or property injection to pass the logger object to the business objects. The logger should be represented by an interface, not by a concrete class. The business objects should be passed a reference to some class that implements this interface. They should never know where this object is stored. This will enable you to test the business objects outside of the web service.
You can then store the logging object wherever you like. I'd suggest storing it in HttpContext.Current.Items, which is only valid for the current request.
public interface ILogger
{
void Log(string message);
}
public class Logger : ILogger
{
public void Log(string message) {}
}
public class BusinessObjectBase
{
public BusinessObjectbase(ILogger logger)
{
Logger = logger;
}
protected ILogger Logger {get;set;}
}
public class BusinessObject : BusinessObjectBase
{
public void DoSomething()
{
Logger.Log("Doing something");
}
}
My understanding is that an ASMX class is instantiated for each call. Therefore, it seems like you could instantiate your log-helper class in the ASMX's constructor, and store it in an instance variable. All processing within the ASMX class would reference that instance variable. In that way, the same log-helper instance would be used throughout the lifecycle of a single webservice call, and would NOT be shared across multiple calls.
This would most likely be implemented within a common superclass, from which all your ASMX classes would inherit. Though I guess there's nothing preventing you from implementing it over and over again in every ASMX class, if for some reason you eschew a common superclass.