How can I dynamically set the TransactionTimeout for a WCF service? - c#

I have a requirement to be able to dynamically set the transaction timeout for a WCF service running over MSMQ. I am following the example on MSDN: http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.channeldispatcher.transactiontimeout.aspx. However, the timeout that I am setting does not seem to be working.
The code that I am using to set the TransactionTimeout property is below:
ServiceProperties properties = ...; // has a TransactionTimeout value for the service
var serviceHost = new ServiceHost(...);
serviceHost.Open();
var channelDispatchers =
serviceHost.ChannelDispatchers.Select(
cd => new ChannelDispatcher(cd.Listener)).ToArray();
foreach (var channelDispatcher in channelDispatchers)
{
channelDispatcher.TransactionTimeout = properties.TransactionTimeout;
}
When I run my service and put a 2-minute delay in my service implementation, I receive a transaction enlistment error when I try to write to another MSMQ queue:
Exception: An error occurred while sending to the queue: The
transaction specified cannot be enlisted. (-1072824232,
0xc00e0058).Ensure that MSMQ is installed and running. If you are
sending to a local queue, ensure the queue exists with the required
access mode and authorization.
Has anyone been able to get this to work in the past? Any ideas would be greatly appreciated.
Thank you in advance.

I figured out the right approach. The correct way to do this is to find and modify the ServiceBehaviorAttribute object that is attached to the service description:
var transactionTimeout = TimeSpan.FromSeconds(...);
var behavior = serviceHost.Description.Behaviors.Find<ServiceBehaviorAttribute>();
behavior.TransactionTimeout = transactionTimeout.ToString();
serviceHost.Open();

Related

check the WCF is availabe or not in c#

I am trying to get the service from a website ,so i connect to the webService like this :
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress address = new EndpointAddress(domainAddress+"/services/reportSRC.svc");
ChannelFactory<IReportSRC> factory = new ChannelFactory<IReportSRC>(binding, address);
IReportSRC channel = factory.CreateChannel();
So but sometimes the service is not available .how can i check this ability ?i mean if the service is available i connect to it otherwise show the error the service is not available
Suppose i have a list that contains several services and a state ,if the service is available the state is true otherwise is false.
you can always use a try-catch block and call the method for testing purpose of your choice.
try
{
serviceClient.AnyMethod();
}
catch
{
//Service not available
}

Unable to track down error for WCF client created with CreateChannelWithIssuedToken

This is a followup of this question here. Might not be directly related to that.
I am trying to call a web service secured with a token (federated security, WS-Trust 1.3) which I obtain from a Secure Token Service. I have the SecurityToken (generic XML) and I create a ChannelFactory<T> on which I then call CreateChannelWithIssuedToken.
The actual error appears when I attempt to invoke a service method. The message is very short and I actually have no idea where to look next: MessageSecurityException and message Unable to create token reference. Well, that can mean anything.
The relevant code:
var binding = new WS2007FederationHttpBinding(WSFederationHttpSecurityMode.TransportWithMessageCredential);
binding.Security.Message.EstablishSecurityContext = false;
var factory = new ChannelFactory<IService>(
binding,
new EndpointAddress("..."));
factory.Credentials.SupportInteractive = false;
var token = STSClient.Issue();
_channel = factory.CreateChannelWithIssuedToken(token);
And calling the service is:
var svcParams = ...;
//MessageSecurityException is thrown here
var svcResponse = _channel.SomeServiceMethod(params);
What I would like to know is where can I look next. What could cause this error ?
Additional details:
The error is thrown before any request is made to the server (checked with Fiddler).
The server is not WCF based. It's some service that complies to WS-Trust and WS-Security.
Actually, the issue was insufficient configuration of the federation binding. Because I already have the token and it is already signed I should have set the IssuedKeyType on the message security to SecurityKeyType.BearerKey.
By playing further with this turns out that Unable to create token reference is thrown every time when there are, well, not enough details to embed the token in the request (typically it's missing configuration on the binding or on the binding's TransportSecurityBindingElement).
This does not completely solve the entire "calling the service with a token" issue, but it does solve this particular error:
var binding = new WS2007FederationHttpBinding(WSFederationHttpSecurityMode.TransportWithMessageCredential);
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Message.IssuedKeyType = SecurityKeyType.BearerKey;
binding.Security.Message.NegotiateServiceCredential = false;

Scaling out SignalR with SQL Server - is it possible to add messages from an outside service?

I am using SQL Server as a backplane for scaling out my SignalR.
In my scenario there are some services which run on other servers and I need to integrate their working status into my SignalR hub.
I tried as a test running a simple Console application with the SQL server scaleout and publish a message like this:
var config = new SqlScaleoutConfiguration(connectionString);
GlobalHost.DependencyResolver.UseSqlServer(connectionString);
var messageBus = new SqlMessageBus(GlobalHost.DependencyResolver, config);
var message = new Message("TransactionHub", "RegisterClient","{userId:1}");
messageBus.Publish(message);
Can I use the SQLScaleout like this somehow?
If not, is there some other way to do what I am trying to do?
Edit:
I've done as halter73 suggested and it works ok, you have to notice that if you activate a client side function, the parameter you send has to match, ie if the object is "Namespace.ClassName" then you should send an object of the same type exactly.
You should try using GlobalHost.ConnectionManager.GetHubContext instead of publishing to the bus directly. Your code would look something like this:
var context = GlobalHost.ConnectionManager.GetHubContext<TransactionHub>();
context.Clients.All.registerClient(new { userId = 1 });

Correcty handle Expectation failed (417) and change Expect100Continue in WCF client app

My application is a C# Windows service that consumes a WCF service. When the first "Expectation failed (417)" error occurs, I change both ServicePointManager.Expect100Continue and ServicePoint.Expect100Continue to false:
try
{
//ServicePointManager.Expect100Continue = false; // If uncomment all work
var svc = new ServiceClient();
svc.GetData(); // first error
}
catch (ProtocolException pex)
{
if (pex.Message.Contains("(417)"))
{
ServicePointManager.Expect100Continue = false;
var sp = ServicePointManager.FindServicePoint(new Uri(#"http://addr.to.service/service.svc"));
sp.Expect100Continue = false;
var svc = new ServiceClient();
svc.GetData(); // second same error
}
}
However, the second call to the service also fails. But if I set Expect100Continue to false before any connection, communication with the service works correctly.
Is this way correctly to handle Expect100Continue errors? I need the application adapts automatically without user action. What am I forgetting to do this work?
Most of the settings on ServicePointManager are treated as the default values applied on all NEW ServicePoints that are created after that point in the application's life. In the case where you change the setting after seeing the error, you are not actually changing anything on existing ServicePoint instances, including the instance associated with the connection used by WCF in this case.
In your Sample code you are calling ServicePointManager.FindServicePoint to try to find the correct ServicePoint. However, FindServicePoint has several overloads and it is easy to use that API incorrectly. For instance, FindServicePoint will try to take into account things http/https, the host you are connecting to, your proxy configuration, etc. If you are not providing the correct parameters to FindServicePoint, you can easily end up getting the wrong ServicePoint returned to you and your settings will not be applied to the ServicePoint you intended to change.
I would recommend that you use the FindServicePoint overload that takes an IWebProxy object to ensure that you get the right ServicePoint. In most cases, you should be able to pass in WebRequest.DefaultWebProxy as the IWebProxy object.
From the MSDN documentation of ServicePointManager.Expect100Continue,
Changing the value of this property does not affect existing ServicePoint objects. Only new ServicePoint objects created after the change are affected. Therefore changing the value on the existing WCF client will have no effect. You need to create a new WCF client, then call GetData()

WCF NetTcpBinding - from Microsoft tutorial - getting timeout

I built a project as descripted in this URL:
http://msdn.microsoft.com/en-us/library/ms734784.aspx
I used the app.config version. But using the code-Version does not change anything (the timeout-error still occurs).
To create the ServiceHost I used the following code:
this.serviceHost = new ServiceHost(typeof(Calculator));
// Open the ServiceHostBase to create listeners and start
// listening for messages.
this.serviceHost.Open();
On the client side I used the following code:
ChannelFactory<ICalculator> factory = new ChannelFactory<ICalculator>("netTcp_ICalculator");
ICalculator communicationChannel = this.factory.CreateChannel();
string test = communicationChannel.GetData(5);
On the last line the program waits one minute, then I get a timeout:
This request operation sent to net.tcp://localhost:8008/Calculator did not
receive a reply within the configured timeout (00:01:00).
The time allotted to this operation may have been a portion
of a longer timeout. This may be because the service is still
processing the operation or because the service was unable to
send a reply message. Please consider increasing the operation
timeout (by casting the channel/proxy to IContextChannel and
setting the OperationTimeout property) and ensure that the service
is able to connect to the client.
The class Calculator and the interface exist. Besides this timeout I get no other error. I set a breakpoint at the GetData method, but the breakpoint was not hit.
I have tried to change the portnumber used for the client from 8008 to 8009, but let the endpoint for the server at 8008. I wanted to test if the client tries to reach the server. Then I get the error that the other side is not answering (EndpointNotFoundException).
When changing the client port back to 8008 I get the Timeout error again.
Is there anything wrong with my code?
How can I ensure that the server can reach the client?
Client and server are in the same test application.
Thank you for your help!
EDIT:
I have now deleted the app.config settings. And tried to build the server and client by using the sourcecode. To build the server was no problem. But building the client is a problem.
There is no way to call:
CalculatorClient cc = new CalculatorClient(myBinding, myEndpointAddress);
The compiler does not know CalculatorClient.
Can I use the following instead?
NetTcpBinding myBinding = new NetTcpBinding();
myBinding.Security.Mode = SecurityMode.None;
// Create the address string, or get it from configuration.
string tcpUri = "net.tcp://localhost:8008/Calculator";
// Create an endpoint address with the address.
EndpointAddress myEndpointAddress = new EndpointAddress(tcpUri);
ChannelFactory<ICalculator> factory = new ChannelFactory<ICalculator>(myBinding, myEndpointAddress);
factory.Open();
ICalculator communicationChannel = this.factory.CreateChannel();
string test = communicationChannel.GetData(5);
I get again an exception at the last line :(
SOLVED:
Ok, the problem is solved. I needed to call the WCF host initialization via an own thread:
hostThread = new Thread(this.createService);
hostThread.Start();
Now everything works fine!
Thanks for all your help!
You are not adding any endpoints to the service.
You did not include the part of the example code that adds the service endpoint:
Uri tcpUri = new Uri("net.tcp://localhost:8008/Calculator");
// Create the ServiceHost.
ServiceHost sh = new ServiceHost(typeof(Calculator), tcpUri);
// Create a binding that uses TCP and set the security mode to none.
NetTcpBinding b = new NetTcpBinding();
b.Security.Mode = SecurityMode.None;
// Add an endpoint to the service.
sh.AddServiceEndpoint(typeof(ICalculator), b, "");
// Open the service and wait for calls.
sh.Open();
Edit: Same goes for your client. You have to specify an endpoint addresses
// Create a channel factory.
NetTcpBinding b = new NetTcpBinding();
b.Security.Mode = SecurityMode.None;
Uri tcpUri = new Uri("net.tcp://localhost:8008/Calculator");
ChannelFactory<ICalculator> myChannelFactory = new ChannelFactory<ICalculator>(b,new EndpointAddress(tcpUri));
// Create a channel.
ICalculator calculator = myChannelFactory.CreateChannel();
Edit2: I can't currently test this code... Will give it a try tomorrow morning.
Are you using Windows 7?
If so, you likely need to run Visual Studio as an Administrator. UAC will not let you create the service endpoint unless you are a running as an administrator.

Categories

Resources