What does System.ServiceModel.Clientbase.Open() do? - c#

What does System.ServiceModel.Clientbase.Open() do? I've never used it but just came across it in some code. Can it throw exceptions? If Close() is not called is it a problem?

If you create a proxy for a WCF service the proxy is effectively ClientBase
Example from my app:
public class DataClient : ClientBase<Classes.IDataService>, Classes.IDataService
{
public DataClient(string connectToHost)
: base(new NetTcpBinding(SecurityMode.Transport)
{
PortSharingEnabled = true,
Security = new NetTcpSecurity()
{
Transport = new TcpTransportSecurity()
{
ClientCredentialType = TcpClientCredentialType.Windows
}
}
},
new EndpointAddress(string.Format("net.tcp://{0}:5555/MyService",connectToHost)))
{ }
#region IDataService Members
public Classes.Folder GetFolder(string entryID)
{
return Channel.GetFolder(entryID);
}
public Classes.IItem GetItem(string entryID)
{
return Channel.GetItem(entryID);
}
#endregion
}
EDIT
Per your request I googled a bit and found this:
Implements ICommunicationObject.Open()
This led to this:
CommunicationException
The ICommunicationObject was unable to
be opened and has entered the Faulted
state.
TimeoutException
The default open timeout elapsed
before the ICommunicationObject was
able to enter the Opened state and has
entered the Faulted state.
Also, per experience and what I've come across on the 'net not closing your clients can cause various forms of strangeness to occur and is thus generally considered "A Bad Thing".

Just found this article:
Best Practice: Always open WCF client proxy explicitly when it is shared
https://blogs.msdn.microsoft.com/wenlong/2007/10/25/best-practice-always-open-wcf-client-proxy-explicitly-when-it-is-shared/
That states in the end:
If you don’t call the “Open” method first, the proxy would be opened internally when the first call is made on the proxy. This is called auto-open.
Why? When the first message is sent through the auto-opened proxy, it will cause the proxy to be opened automatically. You can use .NET Reflector to open the method System.ServiceModel.Channels.ServiceChannel.Call and see the following code:
if (!this.explicitlyOpened)
{
this.EnsureDisplayUI();
this.EnsureOpened(rpc.TimeoutHelper.RemainingTime());
}
When you drill down into EnsureOpened, you will see that it calls CallOnceManager.CallOnce. For non-first calls, you would hit SyncWait.Wait which waits for the first request to complete. This mechanism is to ensure that all requests wait for the proxy to be opened and it also ensures the correct execution order. Thus all requests are serialized into a single execution sequence until all requests are drained out from the queue. This is not a desired behavior in most cases.
To avoid such “serializing” artifact, the best practice is to open the proxy explicitly as above. Once you get to this point, you will be able to share the same proxy object among multiple threads.

Related

SignalR: GetHubContext does not call client methods, but referencing the hub directly does

I had a troubling issue dealing with SignalR (v 2.4.1) hubs last week, and despite doing enough by the documents, I could not broadcast messages without hacking my way through it. For some extra context, this is a self hosted (Owin) hub attached to a windows service.
MSDN documents, and runtime errors (Using a Hub instance not created by the HubPipeline is unsupported), suggest that we are supposed to get the hub context by calling GlobalHost.ConnectionManager.GetHubContext<ThisTypeOfHub>(), and at that point we can make calls to the client.
(https://learn.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/hubs-api-guide-server#callfromoutsidehub)
When I originally set up calls to the clients, I was doing it this way:
public void OnDisplayMessage(string message)
{
var hub = GlobalHost.ConnectionManager.GetHubContext<ThisTypeOfHub>();
hub.Clients.All.BroadcastToClient(message);
}
The browsers that contained the method and had connected to signalR never got called, however. The clients could call server methods, and even the server methods would send out a callback which the clients responded to, but the hub context could never call out to the client methods when called from outside the hub. In the end, I directly brought back the hub reference in the IoC container, and called out to clients using that, as shown below.
public class LogicWithUI : Logic
{
Hub hub;
public LogicWithUI(IDependencyInjectionContainer container)
{
this.hub = container.Resolve<ThisTypeOfHub>(); // ThisTypeOfHub inherits from Hub
}
public class OnDisplayMessage(string message)
{
try
{
this.hub.Clients.All.DisplayMessage(string);
}
catch (Exception)
{
//do nothing, no webpage has connected yet
}
}
}
This way it is finally working fine (you can see the catch placed there for when an error occurs -- only when no webpages have connected to this yet), but it doesn't make sense.
What would cause the HubContext called from outside the hub to not actually broadcast the method?
Why would the unsupported error get thrown only when no clients are connected?
Are there any obvious mistakes I'm overlooking here?
The primary goal here is to have a functioning product, but I also want to do it the right/documented way. It's a little confusing when that way isn't working.
I also understand I might have left out some important details regarding the SignalR configuration, I can answer any follow up questions, but wanted to start with the basic explanation.

MassTransit Activity Fault with parameters

I am currently using Masstransit in with the Courier pattern.
I´ve set up an Activity which may fail, and I want to be able to subscribe to this failure and act accordingly.
My problem is, even though I can subscribe to the failure, and even see the exception that caused the failure, I am unable to pass any arguments to it.
For testing purposes, supose I have the following activity:
public class MyActivity : ExecuteActivity<MyMessage>
{
public Task<ExecutionResult> Execute(ExecuteContext<MyMessage> context)
{
try
{
// .... some code
throw new FaultException<RegistrationRefusedData>(
new RegistrationRefusedData(RegistrationRefusedReason.ItemUnavailable));
// .... some code
}
catch (Exception ex)
{
return Task.FromResult(context.Faulted(ex));
}
}
}
The problem is in the reason (RegistrationRefusedReason) I am passing as a argument of the exception. If I subscribe a RoutingSlipActivityFaulted consumer, I can almost get all the information I need:
public class ActivityFaultedConsumer : IMessageConsumer<RoutingSlipActivityFaulted>
{
public void Consume(RoutingSlipActivityFaulted message)
{
string exceptionMessage = message.ExceptionInfo.Message; // OK
string messageType = message.ExceptionInfo.ExceptionType; // OK
RegistrationRefusedReason reason = ??????;
}
}
I feel like I am missing something important here, (maybe misusing the pattern?).
Is there any other way to get parameters from a faulted activity ?
So, the case you're describing isn't a Fault. It's a failure to meet a business condition. In this case, you wouldn't want to retry the transaction, you'd want to terminate it. To notify the initiator of the routing slip, you'd Publish a business event signifying that the transaction was not completed due to the business condition.
For instance, in your case, you may do something like:
context.Publish<RegistrationRefused>(new {
CustomerId = xxx,
ItemId = xxxx,
Reason = "Item was unavailable"
});
context.Terminate();
This would terminate the routing slip (the subsequent activities would not be executed), and produce a RoutingSlipTerminated event.
That's the proper way to end a routing slip due to a business condition or rule. Exceptions are for exceptional behavior only, since you'll likely want to retry them to handle the failure.
Kinda raising this from the dead, but I really haven't found a neat solution to this.
Here is my scenario:
I want to implement a request/response, but I want to wait for the execution of a routing slip.
As Fabio, I want to compensate for any previous activities and I want to pass data back to the request client in case of a fault.
Conveniently, Chris provided a RoutingSlipRequestProxy/RoutingSlipResponseProxy which does just that. I've found 2 approaches, but both of them seem very hacky to me.
Approach 1:
The request client waits for ISimpleResponse or ISimpleFailResponse.
RoutingSlipRequestProxy sets the ResponseAddress in the variables.
The activity sends ISimpleFailResponse to the ResponseAddress.
The client waits for either response
The RoutingSlipResponseProxy sends back Fault<ISimpleResponse> to the ResponseAddress.
From what I see the hackiness comes from step 4/5 and their order. I am pretty sure it works, but it could easily stop working in case messages are consumed out-of-order.
Sample code: https://github.com/steliyan/Sample-RequestResponse/commit/3fcb196804d9db48617a49c7a8f8c276b47b03ef
Approach 2:
The request client waits for ISimpleResponse or ISimpleFailResponse.
The activity calls ReviseItirery with the variables and adds a faulty activity.*
The faulty activity faults
The RoutingSlipResponseProxy2 get the ValidationErrors and sends back ISimpleFailResponse to the ResponseAddress.
* The activity needs to be Activity and not ExecuteActivity because there is no overload of ReviseItinerary with variables but with no activity log.
This approach seems hacky because an additional fault activity is added to the itinerary, just to be able to add a variable to the routing slip.
Sample code: https://github.com/steliyan/Sample-RequestResponse/commit/e9644fa683255f2bda8ae33d8add742f6ffe3817
Conclusion:
Looking at MassTransit code, it doesn't seem like a problem to add a FaultedWithVariables overload. However, I think Chris' point is that there should be a better way to design the workflow, but I am not sure about that.

How to deal with WCF connection failing

Let's imagine I have WCF service and a client that consumes some methods from a given service.
There are tons of posts of how to handle various exceptions during the client and service communication. Only thing which is still confusing me is a following case:
Service:
[ServiceContract]
public interface IService1
{
[OperationContract]
bool ExportData(object data);
}
public class Service1 : IService1
{
public bool ExportData(object data)
{
// Simulate long operation (i.e. inserting data to the DB)
Thread.Sleep(1000000);
return true;
}
}
Client:
class Program
{
static wsService1.Service1Client client1 = new wsService1.Service1Client();
static void Main(string[] args)
{
object data = GetRecordsFromLocalDB();
bool result = client1.ExportData(data);
if (result)
{
DeleteRecordsFromLocalDB();
}
}
}
Client gets some data from local db and sending it to the server. If result is successful, then client is going to remove exported rows from local DB. Now imagine, when data is already sent to the server, suddenly connection failed (i.e. WiFi was disconnected). In this case data is successfully processed on a server side, but client is never know about it. And yes, I can catch connection exception, but still I don't know what should I do with a records in my local DB. I can send this data again later, but I'll get some duplication on a server DB (i.e. duplication is allowed on remote DB), but I don't want to send same data multiple times.
So, my question is how to handle such cases? What is the best practices?
I checked some info about asynchronous operations. But still this is about when I have stable connection.
As a workaround I can store my export operation under some GUID remotelly and check status for this GUID later. Only thing I can't change remote DB. So, please, suggest what would be better in my case?
Here are some points to consider
On server side you can catch all kinds of error (custom class deriving IErrorHandler) and provide specific error to client letting him know about error's reason.
The concept of service is that it is kind of intermediary between client and database so why would client retrieve data and then send it to service?
One way out is to use transaction which assures that if error occurres then no changes are going to be retained.
By the way, If you expect service to throw an exception do not create global service object since it will end up being in faulted state. Create new instance for every single call instead (make use of using statement so as to dispose its instance). Bool return type does not provide extensive information about the error if any takes place. Let it have void return type and wrap in try/catch block which gives a change to learn more about the source and nature of error.

SslStream, disable session caching

The MSDN documentation says
The Framework caches SSL sessions as they are created and attempts to reuse a cached session for a new request, if possible. When attempting to reuse an SSL session, the Framework uses the first element of ClientCertificates (if there is one), or tries to reuse an anonymous sessions if ClientCertificates is empty.
How can I disable this caching?
At the moment I am experiencing a problem with a reconnect to a server (i.e., the first connection works good, but at attempt to reconnect the servers breaks the session). Restarting the application helps (but of course only for the first connection attempt). I assume the problem root is caching.
I've checked the packets with a sniffer, the difference is at just single place only at Client Hello messages:
First connection to the server (successful):
Second connection attempt (no program restart, failed):
The difference seems to be just the session identifier.
P.S. I'd like to avoid using 3rd-party SSL clients. Is there a reasonable solution?
This is a translation of this question from ru.stackoverflow
Caching is handled inside SecureChannel - internal class that wraps SSPI and used by SslStream. I don't see any points inside that you can use to disable session caching for client connections.
You can clear cache between connections using reflection:
var sslAssembly = Assembly.GetAssembly(typeof(SslStream));
var sslSessionCacheClass = sslAssembly.GetType("System.Net.Security.SslSessionsCache");
var cachedCredsInfo = sslSessionCacheClass.GetField("s_CachedCreds", BindingFlags.NonPublic | BindingFlags.Static);
var cachedCreds = (Hashtable)cachedCredsInfo.GetValue(null);
cachedCreds.Clear();
But it's very bad practice. Consider to fix server side.
So I solved this problem a bit differently. I really didn't like the idea of reflecting out this private static method to dump the cache because you don't really know what you're getting into by doing so; you're basically circumventing encapsulation and that could cause unforeseen problems. But really, I was worried about race conditions where I dump the cache and before I send the request, some other thread comes in and establishes a new session so then my first thread inadvertently hijacks that session. Bad news... anyway, here's what I did.
I stopped to think about whether or not there was a way to sort of isolate the process and then an Android co-worker of mine recalled the availability of AppDomains. We both agreed that spinning one up should allow the Tcp/Ssl call to run, isolated from everything else. This would allow the caching logic to remain intact without causing conflicts between SSL sessions.
Basically, I had originally written my SSL client to be internal to a separate library. Then within that library, I had a public service act as a proxy/mediator to that client. In the application layer, I wanted the ability to switch between services (HSM services, in my case) based on the hardware type, so I wrapped that into an adapter and interfaced that to be used with a factory. Ok, so how is that relevant? Well it just made it easier to do this AppDomain thing cleanly, without forcing this behavior any other consumer of the public service (the proxy/mediator I spoke of). You don't have to follow this abstraction, I just like to share good examples of abstraction whenever I find them :)
Now, in the adapter, instead of calling the service directly, I basically create the domain. Here is the ctor:
public VCRklServiceAdapter(
string hostname,
int port,
IHsmLogger logger)
{
Ensure.IsNotNullOrEmpty(hostname, nameof(hostname));
Ensure.IsNotDefault(port, nameof(port), failureMessage: $"It does not appear that the port number was actually set (port: {port})");
Ensure.IsNotNull(logger, nameof(logger));
ClientId = Guid.NewGuid();
_logger = logger;
_hostname = hostname;
_port = port;
// configure the domain
_instanceDomain = AppDomain.CreateDomain(
$"vcrypt_rkl_instance_{ClientId}",
null,
AppDomain.CurrentDomain.SetupInformation);
// using the configured domain, grab a command instance from which we can
// marshall in some data
_rklServiceRuntime = (IRklServiceRuntime)_instanceDomain.CreateInstanceAndUnwrap(
typeof(VCServiceRuntime).Assembly.FullName,
typeof(VCServiceRuntime).FullName);
}
All this does is creates a named domain from which my actual service will run in isolation. Now, most articles that I came across on how to actually execute within the domain sort of over-simplify how it works. The examples typically involve calling myDomain.DoCallback(() => ...); which isn't wrong, but trying to get data in and out of that domain will likely become problematic as serialization will likely stop you dead in your tracks. Simply put, objects that are instantiated outside of DoCallback() are not the same objects when called from inside of DoCallback since they were created outside of this domain (see object marshalling). So you'll likely get all kinds of serialization errors. This isn't a problem if running the entire operation, input and output and all can occur from inside myDomain.DoCallback() but this is problematic if you need to use external parameters and return something across this AppDomain back to the originating domain.
I came across a different pattern here on SO that worked out for me and solved this problem. Look at _rklServiceRuntime = in my sample ctor. What this is doing is actually asking the domain to instantiate an object for you to act as a proxy from that domain. This will allow you to marshall some objects in and out of it. Here is my implemenation of IRklServiceRuntime:
public interface IRklServiceRuntime
{
RklResponse Run(RklRequest request, string hostname, int port, Guid clientId, IHsmLogger logger);
}
public class VCServiceRuntime : MarshalByRefObject, IRklServiceRuntime
{
public RklResponse Run(
RklRequest request,
string hostname,
int port,
Guid clientId,
IHsmLogger logger)
{
Ensure.IsNotNull(request, nameof(request));
Ensure.IsNotNullOrEmpty(hostname, nameof(hostname));
Ensure.IsNotDefault(port, nameof(port), failureMessage: $"It does not appear that the port number was actually set (port: {port})");
Ensure.IsNotNull(logger, nameof(logger));
// these are set here instead of passed in because they are not
// serializable
var clientCert = ApplicationValues.VCClientCertificate;
var clientCerts = new X509Certificate2Collection(clientCert);
using (var client = new VCServiceClient(hostname, port, clientCerts, clientId, logger))
{
var response = client.RetrieveDeviceKeys(request);
return response;
}
}
}
This inherits from MarshallByRefObject which allows it to cross AppDomain boundaries, and has a single method that takes your external parameters and executes your logic from within the domain that instantiated it.
So now back to the service adapter: All the service adapters has to do now is call _rklServiceRuntime.Run(...) and feed in the necessary, serializable parameters. Now, I just create as many instances of the service adapter as I need and they all run in their own domain. This works for me because my SSL calls are small and brief and these requests are made inside of an internal web service where instancing requests like this is very important. Here is the complete adapter:
public class VCRklServiceAdapter : IRklService
{
private readonly string _hostname;
private readonly int _port;
private readonly IHsmLogger _logger;
private readonly AppDomain _instanceDomain;
private readonly IRklServiceRuntime _rklServiceRuntime;
public Guid ClientId { get; }
public VCRklServiceAdapter(
string hostname,
int port,
IHsmLogger logger)
{
Ensure.IsNotNullOrEmpty(hostname, nameof(hostname));
Ensure.IsNotDefault(port, nameof(port), failureMessage: $"It does not appear that the port number was actually set (port: {port})");
Ensure.IsNotNull(logger, nameof(logger));
ClientId = Guid.NewGuid();
_logger = logger;
_hostname = hostname;
_port = port;
// configure the domain
_instanceDomain = AppDomain.CreateDomain(
$"vc_rkl_instance_{ClientId}",
null,
AppDomain.CurrentDomain.SetupInformation);
// using the configured domain, grab a command instance from which we can
// marshall in some data
_rklServiceRuntime = (IRklServiceRuntime)_instanceDomain.CreateInstanceAndUnwrap(
typeof(VCServiceRuntime).Assembly.FullName,
typeof(VCServiceRuntime).FullName);
}
public RklResponse GetKeys(RklRequest rklRequest)
{
Ensure.IsNotNull(rklRequest, nameof(rklRequest));
var response = _rklServiceRuntime.Run(
rklRequest,
_hostname,
_port,
ClientId,
_logger);
return response;
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
public void Dispose()
{
AppDomain.Unload(_instanceDomain);
}
}
Notice the dispose method. Don't forget to unload the domain. This service implements IRklService which implements IDisposable, so when I use it, it used with a using statement.
This seems a bit contrived, but it's really not and now the logic will be run on it's own domain, in isolation, and thus the caching logic remains intact but non-problematic. Much better than meddling with the SSLSessionCache!
Please forgive any naming inconsistencies as I was sanitizing the actual names quickly after writing the post.. I hope this helps someone!

Is it possible to track all outgoing WCF call?

Our application calls external services like
//in client factory
FooServiceClient client = new FooServiceClient(binding, endpointAddress);
//in application code
client.BarMethod(); //or other methods
Is it possible to track all of these calls (e.g by events or something like that) so that the application can collect the statistics like number of call, response time, etc? Note that my application itself needs to access the values, not only to write to a log file.
What I can think is to create a subclass of VisualStudio-generated FooServiceClient and then add codes like this
override void BarMethod()
{
RaiseStart("BarMethod");
base.BarMethod();
RaiseEnd("BarMethod);
}
and the RaiseStart and RaiseEnd method will raise events that will be listened by my code.
But this seems tedious (because there are a lot of methods to override) and there is a lot of repeated codes, my code needs to change everytime the service contract changes, etc. Is there a simpler way to achieve this, for example by using reflection to create the subclass or by tapping into a built-in method in WCF, if any?
The first thing I would look at is to see if the counters available in your server's Performance Monitor can provide you with the kind of feedback you need. There's built in counters for a variety of metrics for ServiceModel Endpoints, Operations and Services. Here is some more info http://msdn.microsoft.com/en-us/library/ms735098.aspx
You could try building an implementation of IClientMessageInspector, which has a method to be called before the request is sent and when the reply is received. You can inspect the message, make logs etc in these methods.
You provide an implementation of IEndpointBehavior which applies your message inspector, and then add the endpoint behavior to your proxy client instance.
client.Endpoint.Behaviors.Add(new MyEndpointBehavior())
Check out the docs for MessageInspectors and EndpointBehaviors, there are many different ways of applying them (attributes, code, endpoint xml config), I can't remember of the top of my head which apply to which, as there also IServiceBehavior and IContractBehavior. I do know for sure that the endpoint behaviors can be added to the client proxy collection though.
I found a simple way to do it by using dynamic proxy, for example Castle's Dynamic Proxy.
Firstly, use a factory method to generate your client object
IFooClient GetClient()
{
FooClient client = new FooClient(); //or new FooClient(binding, endpointAddress); if you want
ProxyGenerator pg = new ProxyGenerator();
return pg.CreateInterfaceProxyWithTarget<IFoo>(client, new WcfCallInterceptor());
}
And define the interceptor
internal class WcfCallInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
try
{
RaiseStart(invocation.Method.Name);
invocation.Proceed();
}
finally
{
RaiseEnd(invocation.Method.Name);
}
}
//you can define your implementation for RaiseStart and RaiseEnd
}
I can also change the intercept method as I wish, for example I can add a catch block to call a different handler in case the method throw exception, etc.

Categories

Resources