I'm using caliburnMicro on my WPF application.
Beside being UI application, it is also Inter Process communication server (We use WCF over named-pipe).
Each service host is registered as singleton (container.RegisterSingleton(typeof (IMyServiceHost), null, typeof (MyServiceHost));).
Where each implementation of IMyserviceHost holds WCF ServiceHost property.
In current state each service host object request has to open the channel in code after resolving the object.
I want each service host request for resolve will trigger the Open() of the ServiceHost property in order to open the server side channel (this is from the IPC server side).
Is it possible using the exist Caliburn Micro methods?
The registration code:
container.RegisterSingleton(typeof (IMyServiceHost), null, typeof (MyServiceHost));
Then resolve code:
//Resolve the object
var serviceHost = IoC.Get<IMyServiceHost>();
//Then open the channel
serviceHost.Instance.Open();
Take a look at handler registration in the SimpleContainer docs. This allows you to register a func. Essentially you can register something like this:
() => {
var serviceHost = IoC.Get<IMyServiceHost>();
serviceHost.Instance.Open();
return serviceHost;
}
This would assume that you already added IMyServiceHost in the normal manner, that way we can request it with activation or without.
Another option is to do it globally. In the advanced features of the same document you can set up a global activation hook which can do advanced initialisation on any object, simply do a type check and if it is IMyServiceHost then call your required method before returning the object.
Related
I have created WCF service in VS2015:
[ServiceContract(CallbackContract = typeof(IMyCallback))]
public interface IMyService { }
IMyCallback looks like:
[ServiceContract]
public interface IMyCallback {
[OperationContract]
Task<string> OnServerEvent(UserAppEventData evData);
I've built the server, run it, then added service reference (by right click on solution explorer).
The client object is defined as
[CallbackBehaviorAttribute(
ConcurrencyMode = ConcurrencyMode.Reentrant,
IncludeExceptionDetailInFaults = true,
UseSynchronizationContext = true,
ValidateMustUnderstand = true
)]
public class QMyClient : IMyCallback { }
Automatically generated interface implementation made method in sync manner:
public string OnServerEvent(UserAppEventData evData) { }
This code does't work (and isn't asynchronous) and hangs client at OnServerEvent.
When I changed code manuallly to
public async Task<string> OnServerEvent(UserAppEventData evData)
and have done the same in auto generated "service references\...\Reference.cs, all works fine. But I don't want to change Referenece.cs every time I'm updating Service Reference.
Is there any method to force "Update Service Reference" make TBA OperationContractAttribute on callback?
At ordinary WCF service direction everything works OK, VS generates task based operations.
By default the service reference you've added to solution doesn't have asynchronous operations, but you can enable them and decide which option you use for your async methods - task-based or old-fashion asynchronous. This option is available in Advanced settings for service reference.
If you're using a svcutil tool, it will create the task-based methods by default, however, you can change that behavior by some flags like /async or /syncOnly.
What #VMAtm suggested will work out just fine.
I think, you could also use ChannelFactory for this scenario. It is very flexible and you can then await on the service operations from client side. Additional benefit, you don't need to modify client when there are these kind of changes on service side.
Something like:
var channelFactory = new ChannelFactory<IService>(
"WSHttpBinding_IService" // endpoint name
);
IService channel = channelFactory.CreateChannel();
string result = await channel.OnServerEvent();
Console.WriteLine(result);
Please note that for this scenario, you will have to import common interface library to client side as dll because then it will need to know about contracts and data contracts.
I've a service operation which I marked with the Authenticate attribute
[Authenticate]
[Route("/route/to/service", "POST")]
public class OperationA: IReturn<OperationAResponse>
{
...
}
The method IsAuthorized of the AuthProvider is called correctly when I call the service using the REST URL or using JsonServiceClient inside a unit test but is not called if I call the service from ASP.NET code behind (not MVC controller).
I don't use IoC to resolve the service inside my code behind but I use this code...
MyService service = AppHostBase.Instance.Container.TryResolve<MyService>();
service.Post(operationA);
Is there something I'm missing?
Thank you for your attention.
Just to clarify:
I don't use IoC to resolve the service inside my code behind but I use this code...
MyService service = AppHostBase.Instance.Container.TryResolve<MyService>();
You are using the IOC here, i.e. resolving an auto-wired instance of MyService from ServiceStack's IOC.
If you're service doesn't make use of the HTTP Request or Response objects than you can treat it like any normal class and call C# methods. If the service does (e.g. Auth/Registration) then you will also need to inject the current HTTP Request Context as well.
The CustomAuthenticationMvc UseCase project has an example of how to do this:
var helloService = AppHostBase.Resolve<HelloService>();
helloService.RequestContext = System.Web.HttpContext.Current.ToRequestContext();
var response = (HelloResponse)helloService.Any(new Hello { Name = "World" });
I'm using OperationContext.Current.GetCallbackChannel to get a channel to the client that called a WCF service operation.
Do I need to worry about closing / disposing these callback channels or is this taken care of by the framework?
Well, I just tried it myself and it turns out that if you Close & Dispose the callback channel (after casting to IClientChannel) the entire Service channel becomes useless and when called throws a ProtocolException saying:
"This channel can no longer be used to send messages as the output session was auto-closed due to a server-initiated shutdown. Either disable auto-close by setting the DispatchRuntime.AutomaticInputSessionShutdown to false, or consider modifying the shutdown protocol with the remote server."
I assume that this is an unwelcome consequence or side effect of attempting to close & dispose the callback channel, meaning that this should not be done.
In my opinion you should.
The callback mechanism supplies nothing like a higher-level protocol for managing the
connection between the service and the callback endpoint. It is up to the developer to
come up with some application-level protocol or a consistent pattern for managing the
lifecycle of the connection. The service can only call back to the client if the client-side channel is still open, which is typically achieved by not closing the proxy. Keeping the proxy open will also prevent the callback object from being garbage-collected. If the service maintains a reference on a callback endpoint and the client-side proxy is closed or the client application itself is gone, when the service invokes the callback it will get an ObjectDisposedException from the service channel. It is therefore preferable for the client to inform the service when it no longer wishes to receive callbacks or when the client application is shutting down. To that end, you can add an explicit Disconnect() method to the service contract. Since every method call carries the callback reference with it, in the Disconnect() method the service can remove the callback reference from its internal store.
here is an exemple :
class MyService : IServiceContract
{
static List<IServiceContractCallback> m_Callbacks = new List<IServiceContractCallback>();
public void Connect()
{
IServiceContractCallbackcallback = OperationContext.Current.GetCallbackChannel<IServiceContractCallback>();
if(m_Callbacks.Contains(callback) == false)
{
m_Callbacks.Add(callback);
}
}
public void Disconnect()
{
IServiceContractCallback callback = OperationContext.Current.GetCallbackChannel<IServiceContractCallback>();
if(m_Callbacks.Contains(callback))
{
m_Callbacks.Remove(callback);
}
else
{
throw new InvalidOperationException("Cannot find callback");
}
}
In such a way a client can inform the service that the callback is no longer needed. Does it answer your question ?
I have a class that implements a plugin for an existing application.
I also have exposed that class as a WCF service. That part is working so far. The problem I am running into is that the application I am plugging into creates the instance of my class that I want to use.
Is there a way to pass an existing class instance to the WCF service host, to expose as a service endpoint?
I know (or can figure out) how to make a singleton instance of a WCF service, but that still won't help me. From what I can tell, the singleton instance will still be created and provided by WCF.
I have thought of other approaches, but I'd rather take this one if it is available to me.
Some code. This is in the constructor of my plugin:
// Setup the service host
var baseAddress = new Uri("http://localhost:8080/MyService/");
this.serviceHost = new ServiceHost(this.GetType(), baseAddress);
// Add our service endpoint
// Todo: Is there somewhere around here that I can provide an instance?
// Maybe in behavior somewhere?
this.serviceHost.AddServiceEndpoint(
typeof(ITheInterfaceMyClassDerivesFrom),
new BasicHttpBinding(),
""
);
// Add metadata exchange (so we see something when we go to that URL)
var serviceMetadataBehavior = this.serviceHost.Description.Behaviors
.Find<ServiceMetadataBehavior>();
if (serviceMetadataBehavior == null)
this.serviceHost.Description.Behaviors.Add(new ServiceMetadataBehavior());
this.serviceHost.AddServiceEndpoint(
typeof(IMetadataExchange),
new CustomBinding(new HttpTransportBindingElement()),
"MEX"
);
This is in the plugin's OnStartedUp method (called by the application I am plugging into):
serviceHost.Open();
You need to use the other constructor for ServiceHost if you want to do this - check out the MSDN docs at http://msdn.microsoft.com/en-us/library/ms585487.aspx
public ServiceHost(
Object singletonInstance,
params Uri[] baseAddresses
)
How do I test the state of my proxy before making calls to my WCF service.
I have a duplex channel created using a duplex channel factory.
Before making any calls to the server I want to check the state of the proxy object created from the channel factory.
I saw this in a book... (to be used in immediate window)
? ((ICommunicationObject)flsProxy).State
But it gave this exception...
Cannot obtain fields or call methods on the instance of type 'System.ServiceModel.ICommunicationObject' because it is a proxy to a
remote object.
Is it better to just catch exceptions?
If you create your client proxy using a DuplexChannelFactory<T>, you should get back a regular old WCF channel:
Callbacks myCallbacks = new Callbacks();
DuplexChannelFactory<IMyService> factory =
new DuplexChannelFactory<IMyService>(myCallbacks,
new NetTcpBinding(), new EndpointAddress(.....));
IMyService proxy = factory.CreateChannel();
and you should be able to cast that to a ICommunicationObject and check its state:
ICommunicationObject comobj = (ICommunicationObject)proy;
if(comobj.State != CommunicationState.Faulted)
{
// call the service method
}
Where in this chain of statements does it no longer work for you??