WCF Newbie alert. I'm reading "Learning WCF" and "Programming WCF Services" where both books recommend throwing FaultException<T>. If T is .NET type "DivideByZeroException" and assuming a FaultContract exists with
[FaultContract(typeof(DivideByZeroException))]
on method "Divide", will a non-.NET client consuming that WCF service and method be able to understand and process that .NET exception? If yes, is it because the type info (DivideByZeroException) is part of the metadata (because of the FaultContract) that the client has access to and uses?
Thanks for any help.
You can throw a FaultContract<DivideByZeroException>, but in general you shouldn't do that, exactly for the reason you mentioned (*). What is usually recommended is to have a data contract with the information from the exception, such as the exception message, and then have a FaultContract of that type.
[DataContract]
public class MyErrorDetails
{
[DataMember]
public string ErrorCode { get; set; }
[DataMember]
public string ErrorMessage { get; set; }
}
And then use
[FaultContract(typeof(MyErrorDetails))]
(*) Another reason to avoid returning exceptions as faults is that they disclose more information to the client than the client needs; things such as the stack trace are serialized by the exception, but that's some information internal to the service and shouldn't be sent to clients.
Related
I have a Composite type DataContact and one of the DataMember is a decimal? return type
[DataMember]
public decimal? ExchangeRate { get; set; }
When a value is assigned to the ExchangeRate property from the client, the serialized value across the wire at the service end is null. Why is this happening as WCF 4.5 fully supports Nullable types according to MSDN. Any pointers would be greatly appreciated.
If you have not already, I suggest you enable WCF tracing on the client and service, so you have a better understanding of the serialized values. At least you could confirm the client parameter values and serialization and then compare to the result received by the WCF Service.
For reference: WCF tracing provides diagnostic data for fault monitoring and analysis. You can use tracing instead of a debugger to understand how an application is behaving, or why it faults.http://msdn.microsoft.com/en-us/library/ms733025(v=vs.110).aspx
What is a good way to create a WCF service layer so that a native .Net client application and other client types can talk to the service?
I know, in the future our applicaiton will need to support mobile devices.
We are passing objects into our WCF methods similar to this:
[DataContract]
public class User: DomainBase
{
[DataMember]
public string Username { get; set; }
[DataMember]
public string Password { get; set; }
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
}
So there may be a method in our servcie like this:
public bool Save(User item){
...do some work
}
public User GetUserByUsernameAndPassword(string username, string password){
...do some work
}
Now, in .Net I can use the same object library as my services, but with other clients I will not be able to. So, if I don't want to write a bunch of differnt methods for each type of client what would be the best way to handle this?
I think interoperability with other clients is more dependent on the binding that the actual contracts. If the other clients and client languages that you will support can do SOAP, then sticking with the BasicHttpBinding provides the best support. For example clients using .NET 2 can still interact with a .NET 3.5 WCF server. There area also SOAP libraries for Java and other languages.
The server can just publish the WSDL, and the clients can then generate all your contract interfaces and types automatically in whatever language from the WSDL. That handles the 'reuse' of your data contract types.
If you want to venture away from SOAP, there are ways to do REST or Plain-old-XML or JSON with WCF, but it gets a lot more complicated from the server side...
What you have now should work perfectly for any other client. What leads you to believe there might be a problem?
It depends on which binding you choose to support. Certain bindings only work with .NET.
BasicHttpBinding: SOAP over HTTP. Any SOAP client can connect
WsHttpBinding: - It is same like
BasicHttpBinding. In short, it uses
SOAP over HTTP. But with it also
supports reliable message transfer,
security and transaction. WS-Reliable
Messaging, security with WS-Security,
and transactions with WS-Atomic
Transaction supports reliable
message.
NetTcpBinding: - This
binding sends binary-encoded SOAP,
including support for reliable
message transfer, security, and
transactions, directly over TCP. The
biggest disadvantage of NetTcpBinding
is that both server and client should
be also made in .NET language.
NetNamedPipesBinding:-Ths binding
Sends binary-encoded SOAP over named
pipes. This binding is only usable
for WCF-to-WCF communication between
processes on the same Windows-based
machine.
I understand that WCF will convert an exception into a fault and send it back as a SOAP message, but I was wondering if this is truly interoperable. I guess I'm having a tough time trying to figure out this possible scenario:
Client (Java) calls a WCF Service
(LoginService).
Server checks for proper authorization, user authorization fails.
Server throws an UnauthorizedAccessException.
WCF converts this into a Fault somehow. (* - See Below As Well)
Client has to be able to know how to read this Fault.
I guess I'm just having a tough time understanding how this could still be interoperable because it is expecting Java to know how to translate a SOAP Fault that .NET encodes from an UnauthorizedAccessException.
Also, how does .NET actually convert the exception to a fault, what goes in as the fault code, name, etc. Some of the things seem to be "duh"s like perhaps the Fault Name is "UnauthorizedAccessException", but I'd rather know for sure than guess.
There is no "automatic conversion". WCF will return a fault (I forget which one) when you have an unhandled exception. But since you didn't declare that fault, many, if not most, clients will fail if you return it.
You are meant to define your own faults and to return them instead. Consider:
[DataContract]
public class MySpecialFault
{
public string MyMessage { get; set; }
}
[ServiceContract]
public interface IMyService
{
[FaultContract(typeof (MySpecialFault))]
[OperationContract]
void MyOperation();
}
public class MyService : IMyService
{
public void MyOperation()
{
try
{
// Do something interesting
}
catch (SomeExpectedException ex)
{
throw new FaultException<MySpecialFault>(
new MySpecialFault {MyMessage = String.Format("Sorry, but {0}", ex.Message)});
}
}
}
Any client capable of handling faults will deal with this. The WSDL will define the fault, and they will see a fault with the Detail element containing a serialized version of the MySpecialFault instance that was sent. They'll be able to read all the properties of that instance.
Faults have been part of the SOAP specification since v1.1. They are explained in the SOAP Specification.
It is up to implementations (WCF, Java etc) to ensure that Faults are handled according to the specification.
Since WCF converts FaultExceptions to Faults according to the SOAP specification, FaultExceptions thrown from WCF are interoperable.
SOAP faults are interoperable but .Net exception classes are not good to be used in SOAP faults. Instead define your own DataContract class (e.g. AccessFault) and then use it in a FaultContract.
see http://msdn.microsoft.com/en-us/library/ms733841.aspx
Whenever there is a UnauthorizedAccessException thrown at service boundary convert it to FaultException.
This can be done in several ways like using Microsoft Enterprise Library Exception Handling Block or implementing the IErrorHandler interface.
This has been resolved
This is a contract I'm unable to get from a service call:
[DataContract]
public class myInitializationData : ClientInitializationData
{
[DataMember]
public Dictionary<string, string> CultureNameLookup { get; set; }
}
Here's it's base type,
[DataContract]
public class ClientInitializationData
{
[DataMember]
public List<IServiceType> ServiceTypes { get; set; }
}
IServiceType is an interface. I realize I cannot send an interface across the wire. There is an EntityFramework entity, ServiceType, implementing the IServiceType interface:
public partial class ServiceType : IServiceType
{
//...
}
My goal is to send ServiceType entities across the wire via the myInitializationData contract.
I am prevented from decorating the myInitializationData or ClientInitializationData classes with a KnownType of ServiceType, because these classes are shared (linked) to Silverlight project(s). So if I decorate either of these classes with a KnownType of ServiceType, the Silverlight side(s) will fail to compile.
Instead of decorating the classes directly, I decorated the service contract with with a ServiceKnownType of ServiceType:
[ServiceContract]
[ServiceKnownType(typeof(ServiceType))]
public interface IService
{
[OperationContract]
myInitializationData InitializeClient();
}
Should this work?
When calling IService.InitializeClient, I receive the following error on the client:
There was an error reading from the pipe: The pipe has been ended. (109, 0x6d).
I have enabled trace debugging but found no messages regarding failure to serialize in the trace for either client or server.
Server trace:
Receives a message ever a channel
(Action: http://tempuri.org/IService/InitializeClient)
To: Execute
(IService.InitializeClient)
From: Execute
(IService.InitializeClient)
Sends a message over a channel
(Action: http://tempuri.org/IService/InitializeClientResponse)
Warning
Faulted System.ServiceModel.Channels.ServerSessionPreambleConnectionReader+ServerFramingDuplexSessionChannel
Warning
Faulted System.ServiceModel.Channels.ServiceChannel
Replying to an operation threw an exception
(The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.)
Client trace:
Sends a message over a channel
(Action: http://tempuri.org/IService/InitializeClient)
Throwing an Exception
(There was an error reading from the pipe: The pipe has been ended. (109, 0x6d).)
If I opt the ServiceTypes property out of the ClientInitializationData DataContract, this error goes away. So I assume this must be a serialization issue re: the interface and KnownTypes, but WCF isn't claiming to have any serialization issues in the trace, and I'm not sure what the trace means in this case.
Solution
This was not a KnownTypes issue. It was the result of LazyLoading having been spontaneously enabled on the entity context defining the ServiceType type.
Although there is no mention of excessive message or a buffer sizes being violated in the trace (on either the client or server sides), I must assume the enabling of LazyLoading on the EF context caused the DataContractSerializer to trigger EF into fetching a lot of records, which in turn resulted in a massive graph being (attempted) on the wire. The server side was simply (and ambiguously) faulting the channel during the message write.
Returning LazyLoading to a disabled state on the EF context has since solved this problem.
This was not a KnownTypes issue. It was the result of LazyLoading having been spontaneously enabled on the entity context defining the ServiceType type.
Although there is no mention of excessive message or a buffer sizes being violated in the trace (on either the client or server sides), I must assume the enabling of LazyLoading on the EF context caused the DataContractSerializer to trigger EF into fetching a lot of records, which in turn resulted in a massive graph being (attempted) on the wire. The server side was simply (and ambiguously) faulting the channel during the message write.
Returning LazyLoading to a disabled state on the EF context has since solved this problem.
We are trying to figure out a way to modify WCF service behavior to catch all exceptions and instead of returning faults to the client, it will populate a custom return object with exception data and return that. So far, we haven't had much luck. I found this example: Catching custom faults
However, it doesn't return custom types as we would like it to. What other options are there?
Thanks!
If you want to have an interoperable and "by-the-standard" service, you should always return FaultException<T> SOAP faults from your service to the client.
Since that type takes a generic <T>, you can basically put anything into that type there to report back your errors. That type needs to be decorated with a [DataContract], and its members that need to be passed back with [DataMember] attributes.
[DataContract]
public class MyErrorInfo
{
[DataMember]
public int ErrorCode { get; set; }
[DataMember]
public string ErrorMessage { get; set; }
}
When you catch those execptions on the service side and return a FaultException<MyErrorInfo> (or whatever you'll end up calling your error class), you also need to decorate your operations with a
[FaultContract(typeof(MyErrorInfo))]
[OperationContract]
public SomeType SomeMethodCall(SomeType parameter);
so that your clients will be able to catch the FaultException<MyErrorInfo> and handle it.
I referred to this article in another answer, but it may help you as well..
WCF Exception Handling
the article is Simplifying WCF: Using Exceptions as Faults
I wrote a blog post on this exact topic after we encountered this in our own project. Basically, we chose to return the same object type so we can attach a single listener delegate to all events to globally handle certain errors (like a user losing the permissions to an org.)
I hadn't thought of using FaultException but I will examine how we might do that. This design was WCF Service (.NET 3.5) running inside SharePoint 2007 and consumed by Silverlight 4.