On Server I'm throwing the exception like this.
catch(SqlException exception)
{
if (exception.Message.Contains("Custom error from stored proc"))
{
//Exception to be thrown when authentication fails.
throw new FaultException<MyServiceFault>(new MyServiceFault { MessageText = exception.Message });
}
}
And on client end I'm catching the exception
catch(FaultException<MyServiceFault> faultException)
{
}
Here is my MyServiceFault
[DataContract]
public class MyServiceFault
{
[DataMember]
public string MessageText { get; set; }
[DataMember]
public Guid Id { get; set; }
}
The problem is that on client, it doesn't go to MyServiceFault catch block instead it goes to communication exception catch block and throws this error
System.ServiceModel.CommunicationException: The underlying connection was closed: The connection was closed unexpectedly. ---> System.Net.WebException
I've also decorated my service method [FaultContract(typeof(MyServiceFault))] in the interface which is implemented by my service.
In my web.config servicebehaviour tag consist
<serviceDebug includeExceptionDetailInFaults="true" />
Any idea where I'm going wrong.
This problem is occurring on windows 7. Can there be a reason related to it?
IMPORTANT UPDATE
According to answerers, any unhandled exception on the server can cause throwing of the Communication exception on the client side and it may not have anything to do with the custom fault exception you have thrown on the server. So the solution is log the errors on the server and find what error is causing this behavior. Here is a very useful open source logging functionality I found and implemented which can even be more useful after your project goes into production environment. Many thanks to the answerers.
A better way of logging exceptions in WCF
Add logging to your WCF calls by including this in your app.config.
<system.diagnostics>
<trace autoflush="true" />
<sources>
<source name="System.ServiceModel" switchValue="Information, ActivityTracing">
<listeners>
<add name="sdt" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\LogPath\LogFile.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
(You can do this for both server and client, obviously specifying different log files)
Once you've generated some logs, look through for exceptions or warnings. I often find this produces some very useful information that helps me solve WCF problems.
To read the log file, you'll need to use SvcTraceViewer.exe. Unfortunately the only way to get this is with the windows SDK which is a bit of a big download for one tiny little tool.
It's also worth bearing in mind that WCF can through the CommunctionException when it is being closed, and this is expected behaviour. You shouldn't just do using with client WCF comm channels. Instead, you should follow a pattern like this:
try{
x.Close()
}
catch(Comms ex){
x.Abort()
}
One thing i learned from working with wcf is that the error CommunicationException is thrown alot of times. It is even possible that the error you get has nothing to do with the Exception you throw, but with something else causing it. At the moment something is being sent between a client and server, it's hard to track down what is causing the exception.
I could solve some of my issues by adjusting some settings in the app.config. Setting timeout, etc...
Maybe that can help?
As a follow-up, one reason for getting CommunicationException is that the FaultException could not be serialized correctly. In the log (see Simon's answer on how to set up logging), this would show up as "Handling exception" followed by "Replying to an operation threw an exception".
In my case, this was caused by not initializing an enumeration value:
[DataContract]
public class MyCustomWebServiceFault
{
public MyCustomWebServiceFault()
{
}
[DataMember]
public EMyCustomWebServiceFaultReason Reason { get; set; }
[...]
The log then revealed it:
Enum value '0' is invalid for type 'EMyCustomWebServiceFaultReason' and cannot be serialized. Ensure that the necessary enum values are present and are marked with EnumMemberAttribute attribute if the type has DataContractAttribute attribute.
Long story short, use logging or unit test exception serialization.
Related
How to write custom trace listener to write message logs in msmq?
I have added below custom MSMQTraceListener :
public class MSMQTraceListener : TraceListener
{
string _queueName;
public MSMQTraceListener(string queueName)
: base("MSMQListener")
{
_queueName = queueName;
if (!MessageQueue.Exists(_queueName))
MessageQueue.Create(_queueName);
}
public override void Write(string message)
{
SendMessageToQueue(message);
}
public override void WriteLine(string message)
{
SendMessageToQueue(message);
}
/// <summary>
/// Send message to queue.
/// </summary>
/// <param name="message">string: message</param>
private void SendMessageToQueue(string message)
{
try
{
MessageQueue messageQueue = new MessageQueue(_queueName, QueueAccessMode.Send);
messageQueue.Label = DateTime.Now.ToString();
messageQueue.Send(message);
messageQueue.Close();
}
catch (Exception ex)
{
}
}
}
And updated below diagnostic setting in my web.config file:
<system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="messages" type="Proj.Common.Diagnostics.MSMQTraceListener,Proj.Common" initializeData=".\private$\PerformanceTesting" />
</listeners>
</source>
</sources>
</system.diagnostics>
If you are in code hosted by MSMQ and want to write a message to say a log file
All .NET applications are the same as far as System.Diagnostics is concerned. Configure the listener in app.config, and use Trace or TraceSource to write to the listener. MSDN explains this better than I can.
If you want a trace listener that sends message to MSMSQ
Get this utility library, Essential Diagnostics, that makes working with System.Diagnostics less painful
Override the one TraceEvent() method on BaseTraceListener. Inside that method, you use the available parameters to send messages to whatever you'd like, for example an MSMQ destination.
Register your custom TraceListener in the usual way.
I implemented custom exception handler which works, except mappings from xml configuration policy. Those mapping works with standard Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.LoggingExceptionHandler
My implementation
[ConfigurationElementType(typeof(CustomHandlerData))]
public class IdentityFaultContractExceptionHandler : IExceptionHandler
{
public IdentityFaultContractExceptionHandler(NameValueCollection attributes)
{
}
public IdentityFaultContractExceptionHandler(Type faultContractType, NameValueCollection attributes)
{
}
public IdentityFaultContractExceptionHandler(Type faultContractType, string exceptionMessage, NameValueCollection attributes)
{
}
public IdentityFaultContractExceptionHandler(IStringResolver exceptionMessageResolver, Type faultContractType, NameValueCollection attributes)
{
}
public Exception HandleException(Exception exception, Guid handlingInstanceId)
{
return new Exception();
}
and part of the configuration
<add name="All Exceptions" type="System.Exception, mscorlib" postHandlingAction="ThrowNewException">
<exceptionHandlers>
<add type="MyClass.IdentityFaultContractExceptionHandler, MyClass" exceptionMessage="An error occurred in the service." faultContractType="MyClass.UnexpectedServerFault, MyClass" name="Fault Contract Exception Handler" >
<mappings>
<add source="{Message}" name="Message" />
</mappings>
</add>
</exceptionHandlers>
</add>
When I remove mappping node service works, when I add, then I got error : unrecognize element mappings.
If you are using a CustomHandlerData attribute then your configuration needs to use XML Attributes which then get passed in as a NameValueCollection to the custom handler constructor. If you want to have custom XML then you will have to use Full Design-time Integration. If you want to go down that road then you should look at the FaultContractExceptionHandlerData source code since your code would probably be quite similar.
I have multiple WCF services hosted in IIS to which I'm applying the same custom service behavior. I'm looking for a way to pass several parameters to the behavior through configuration, such as in behaviorExtensions or behavior elements.
If it helps, I'm also adding custom message inspector in ApplyDispatchBehavior, so I will need to pass parameters to the inspector:
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
{
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(
new ValidatingMessageInspector(<custom parameters>));
}
}
}
Would just creating a configuration section in web.config with the parameters be valid? If so you can just read the config there and apply it, or even just use appSettings if the parameters are basic.
For example, if you have few parameters of basic types, maybe a simple approach could be:
<appSettings>
<add key="Shared.CommonParameter" value="A value" />
<add key="Service1.OneParameter" value="False" />
<add key="Service1.AnotherParameter" value="Some Value" />
<add key="Service2.ADifferentParameter" value="42" />
</appSettings>
That way it would be easy to differentiate what setting belongs to which service (notice the service name prefix in the key), and also have some shared parameters if needed.
If you need something more complex in structure you might want to look into defining custom configuration sections for each service, as is shown here: http://msdn.microsoft.com/en-us/library/2tw134k3%28v=vs.140%29.aspx
But that might be overkill, depending on your needs and expected flexibility.
I've been reading up on how to do this but I'm having a hard time getting my head around it.
Synchronous and Asynchronous Operations
WCF: Working with One-Way Calls, Callbacks, An...
My goal is to return results from multiple functions in a Silverlight enabled WCF service as they are discovered.
A general overview of how this service is desired to work is as follows.
User enters a url that has many large csv files listed in hyperlinks. The service gets the initial user entered url, makes a web request of that url, gets the csv file names using regex, service downloads the csv files to server, files are converted to a different format.
Currently all of that works, but no response is shown until the entire operation is done. I would like to provide feedback during each function.
I'm using VB for this app but am fluent in C# if anyone has a code suggestion.
<ServiceContract(Namespace:="http://somemadeupurl")>
<SilverLightFaultBehavior()>
<AspNetCompatibilityRequirements(RequirementsMode:=
AspNetCompatibilityRequirementsMode.Allowed)>
Public Class GetCSV
<OperationContract()>
Public Function ProcessInitialLink(ByVal strInitialLink As String)
'download the source html
'do a webrequest and extract csv links
'since dates are in the filenames I would like to send back most
'recent to user here
Dim strMostRecentCSV As String=SomeRegexMatch
> 'problem here. Would like to return strMostRecentCSV and keep processing
GetAndConvertBigCSV(strMostRecentCSV)
Return strMostRecentCSV
End Function
'actually a list but for brevity..
Private Function GetAndConvertBigCSV(ByVal strMostRecentCSV as string)
'do a bunch of downloading
'call a function to do a bunch of converting
'call a function to clean up files
End Function
End Class
If it's done like this it will return strMostRecentCSV but has to wait until GetAndConvertBigCSV is done before returning.
I've tried spawning GetAndConvertBigCSV as a new thread and it works but returns nothing that I can bind to the Silverlight client (e.Result)
At a minimum I would like to provide feedback of the first function Return then have the service continue.
Thanks a million for help.
I think that what you probably want is a "polling duplex http service" - what this means is that WCF will fake up a duplex style service for you (by polling). The advantage of a duplex service over a regular asynchronous service is that it is easy to call back to the client multiple times (so you can provide feedback on the progress of your task).
It is very easy to implement. Let's say you have two projects a web application and a silverlight application...
Web Application
Create your service, for example:
[ServiceContract(CallbackContract = typeof(ICallback))]
public interface ILongRunningService
{
[OperationContract]
void StartLongRunningProcess(string initialParameter);
}
[ServiceContract]
public interface ICallback
{
[OperationContract(IsOneWay = true)]
void Update(string someStateInfo);
}
public class LongRunningService : ILongRunningService
{
public void StartLongRunningProcess(string initialParameter)
{
// Get hold of the callback channel and call it once a second
// five times - you can do anything here - create a thread,
// start a timer, whatever, you just need to get the callback
// channel so that you have some way of contacting the client
// when you want to update it
var callback = OperationContext
.Current
.GetCallbackChannel<ICallback>();
ThreadPool
.QueueUserWorkItem(o =>
{
for (int i = 0; i < 5; i++)
{
callback.Update("Step " + i);
Thread.Sleep(1000);
}
});
}
}
Then you need a svc file that has this in it (adjust the service attribute to be your service implementation class):
<%# ServiceHost Service="SilverlightApplication.Web.LongRunningService" %>
Finally you will need this configuration inside web.config (this goes inside the configuration root element):
<system.serviceModel>
<extensions>
<bindingExtensions>
<add name=
"pollingDuplexHttpBinding"
type="System.ServiceModel.Configuration.PollingDuplexHttpBindingCollectionElement,System.ServiceModel.PollingDuplex, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</bindingExtensions>
</extensions>
<services>
<service name="SilverlightApplication.Web.LongRunningService">
<endpoint
address=""
binding="pollingDuplexHttpBinding"
bindingConfiguration="multipleMessagesPerPollPollingDuplexHttpBinding"
contract="SilverlightApplication.Web.ILongRunningService">
</endpoint>
<endpoint
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange"/>
</service>
</services>
<bindings>
<pollingDuplexHttpBinding>
<binding name="multipleMessagesPerPollPollingDuplexHttpBinding"
duplexMode="MultipleMessagesPerPoll"
maxOutputDelay="00:00:07"/>
</pollingDuplexHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
The important parts are the name attribute on the service element and the contract attribute on the endpoint element. They should be the class and interface you defined (with the namespace).
IMPORTANT You need to add a reference to the C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\Libraries\ Server\System.ServiceModel.PollingDuplex.dll assembly (remove the x86 if not 64 bit OS) to the web application project.
Silverlight Application
You need to firstly add a service reference to the service you created and then, let's say you want to call the service from a button you would have the following code:
private void button1_Click(object sender, RoutedEventArgs e)
{
// Create the client proxy with the URL of the service
var proxy = new LongRunningServiceClient(
new PollingDuplexHttpBinding(
PollingDuplexMode.MultipleMessagesPerPoll),
new EndpointAddress(
"http://localhost/WebApplication/LongRunningService.svc"));
// Attach the handler to be called periodically and start the process
proxy.UpdateReceived += Update;
proxy.StartLongRunningProcessAsync("blah");
}
private void Update(object sender, UpdateReceivedEventArgs e)
{
// Use the result from the e parameter here
}
IMPORTANT You need to add a reference to the C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\Libraries\ Client\System.ServiceModel.PollingDuplex.dll assembly (remove the x86 if not 64 bit OS) to the silverlight client project.
And that is it - the Update method will get called, in this case once a second five times. but you can do whatever you like.
I would NOT recommend using a polling duplex to solve this business requirement, due to the load it places in the server. What I read was that you have a need to return several files back to the client, and provide feedback to the client as the files are being downloaded.
As downloading a file does not seem to be an issue (which should be a stream), I think you are asking is how to update the UI, while the files are being downloaded, perhaps capturing how much of the file is actually being downloaded. At the least, you should be updating the UI as each file arrives.
The latter is easy, simply download the download links to each file on the client, do them one by one, and update the UI between file downloads. That would be a single threaded approach.
Update the UI while a background thread is executing, is a more complicated approach, but a much better implementation, as the client "feels" that they remain in control while the files are being downloaded. Here is an approach for downloading a file async.
Remember in SilverLight, you really only have HTTP to transfer information to the application, which cannot do duplex. HTTP long pooling achieves the same result, but connections are left open, and greatly minimize the ability to scale.
I'm writing a WCF service with some authentication and a custom error handler. However, I'm coming up against this problem: my implementation of IErrorHandler is not getting hit when the authentication throws an exception, but runs just fine with other exeptions.
Does authentication run before IErrorHandler gets built? Am I barking up the wrong tree trying to get it to catch those errors?
Yes, I have tried (and am) throwing a FaultException in my authentication, not SecurityTokenException.
So first thing is to make sure that your custom Error Handler is also implementing IServiceBehavior. IServiceBehavior requires that you implement a couple other methods but the important one is "ApplyDispatchBehavior", in which you must add the ErrorHandler to the channel dispatchers.
C#
public class CustomErrorHandler: IServiceBehavior, IErrorHandler
{
public bool HandleError(Exception error)
{
//Return True here if you want the service to continue on as if
// the error was handled
return true;
}
public void ProvideFault(Exception error,
MessageVersion version,
ref Message fault)
{
FaultException fe = new FaultException(
new FaultReason(error.Message),
new FaultCode("Service Error"));
MessageFault mf = fe.CreateMessageFault();
fault = Message.CreateMessage(version, mf, fe.Action);
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase)
{
IErrorHandler eh = new CustomErrorHandler();
foreach (ChannelDsipatcherBase cdb in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher cd = cdb as ChannelDispatcher;
cd.ErrorHandlers.Add(eh);
}
}
public void AddBindingParameters(ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase,
Collection<ServiceEndpoint> endpoints,
BindingParameterCollection bindingParameters)
{
//Add binding parameters if you want, I am not
}
public void Validate(ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase)
{
//Add custom fault validation here if you want
}
}
Then you need to add the CustomErrorHandler as a service behavior and add the behavior
web.config
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="ErrorHandler"
type="ServiceNamespace.CustomErrorHandler, ServiceNamespace, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
<behaviors>
<serviceBehaviors>
<behavior name="MyBehavior1">
<!--Put other behaviors for your service here then add the next line-->
<ErrorHandler />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
This way all your thrown exceptions will be converted to faults to return back to the client.
In the case of SecurityTokenExceptions, you do not want to convert those to Fault Exceptions right away. You actually do want to throw these as SecurityTokenExceptions in the custom validation in order for the service/server to recognize that the security authorization failed, and automatically returns as a fault equiv of a "403 : Access Denied". I am not 100% but I think that the custom auth and validation pieces happen before custom service behaviors, like the error handler, are loaded. Unfortunately, if you need to troubleshoot something in your auth, you will need to turn on WCF tracing on the service, see this article titled "How to turn on WCF Tracing".
If you need to log failed auth attempts, you will probably need to put it directly in your custom validator.