FaultException.Detail coming back empty - wcf

I am trying to catch a given FaultException on a WCF client. I basically need to extract a inner description from the fault class so that I can then package it in another exception for the upper layers to do whatever.
I've done this successfully a number of time, what makes it different this time is that fault is declared as an array, as you can see from the service reference attribute declared on top of the method that throws the exception:
[System.ServiceModel.FaultContractAttribute(typeof(FaultClass[]), Action = "http://whatever/", Name = "whateverBusinessFault")]
This is my code:
try
{
// call service here
}
catch (FaultException<FaultClass[]> ex)
{
if (ex.Detail != null && ex.Detail.Length > 0)
{
throw new CustomException(ex.Detail[0].description);
}
else
{
throw;
}
}
Problem is Detail (which is an array) is always coming back empty in the code even if I can see the data (description field etc.) in the SOAP response from WCF trace.
So the stuff I need is definitely coming back but for some reason either it doesn't get deserialized or I can't get to it from code.
Any help appreciated!
UPDATE:
Trying with #Darin suggestion but no luck, the string I am extracting from the XmlReader is "/r/n":
var sb = new StringBuilder();
using (XmlReader reader = fault.GetReaderAtDetailContents())
{
while (reader.Read())
sb.AppendLine(reader.ReadOuterXml());
}
var detail = sb.ToString();
Looks like the detail section is not coming up at all!

I found the solution on a UPS Forum :
https://developerkitcommunity.ups.com/index.php/Special:AWCforum/st/id371
"The problem was the visual studio didn't quite map out the ErrorDetail objects right. The ErrorDetail node is called "ErrorDetail", but the type generated for it is "ErrorDetailType." I edited the reference.cs class generated for each service I was using and added a TypeName:"

It is difficult to say where the problem is but I suspect the smoking gun is this axis web service not generating standard message. One way to workaround this would be to parse the XML yourself:
try
{
proxy.CallSomeMethod();
}
catch (FaultException ex)
{
var fault = ex.CreateMessageFault();
using (XmlReader reader = fault.GetReaderAtDetailContents())
{
// TODO: read the XML fault and extract the necessary information.
}
}

It took me ages to figure out how to get the full details message from a FaultException as a string. I eventually figured it out and wrote this extension method:
public static string GetDetail(this FaultException faultException)
{
if (faultException == null)
throw new ArgumentNullException(nameof(faultException));
MessageFault messageFault = faultException.CreateMessageFault();
if (messageFault.HasDetail) {
using (XmlDictionaryReader reader = messageFault.GetReaderAtDetailContents()) {
return reader.ReadContentAsString();
}
}
return null;
}
Originally I was using reader.Value but that only appeared to the return the first line of a multi-line details message. reader.ReadContentAsString() appears to get the whole thing, new lines included, which is what I wanted.

I came up with the simplest test case I could. I hope it will help you.
Server side:
[ServiceContract]
public interface IService1
{
[OperationContract]
[FaultContract(typeof(FaultClass[]))]
string Crash();
}
public class Service1 : IService1
{
public string Crash()
{
var exception = new FaultException<FaultClass[]>(new FaultClass[] { new FaultClass { Data = "TEST" } }, new FaultReason("Boom"));
throw exception;
}
}
[DataContract]
public class FaultClass
{
[DataMember]
public string Data { get; set; }
}
Client side:
try
{
using (var client = new Service1Client())
{
client.Crash();
}
}
catch(FaultException<FaultClass[]> e)
{
//Break here
}

I had a similar situation in trying to communicate data with faults (specifically a stack trace). See this question. I ended up solving it by creating my own serializable stack trace and including it in a derived FaultException class.

Related

JsonDocument Parse JsonReaderException - xUnit

I thought I found a cleaner way with a smaller footprint to test a string to see if its valid JSON; however when I run a test its failing because its returns a JsonReaderException so when I tried to change the type to this, I get a protection error as it seems to be internal??
I am using System.Text.Json in my project.
How can this be changed so I can use my existing code:
public ApplicationSettings WithTemplate(string template) {
try {
JsonDocument.Parse(template);
baseTemplate = template;
}
catch(JsonException ex) {
throw ex;
}
return this;
}
Test Code:
[Fact]
public void WithTemplate_ThrowsJsonExceptionWhenBaseTemplateIsInvalid() {
Assert.Throws<JsonException>(() => new ApplicationSettings()
.WithTemplate("345[]{}q345"));
}
I found a solution that was just as compact as JsonDocument.Parse() for just checking the validity of string of json with the JsonSerializer.
string malformedJson = "345[]{}q345"
JsonSerializer.Deserialize<object>(malformedJson)
Then I was able to test against the exception JsonException and not have to worry about JsonReaderException

How to create generic deserializer using Google Protocol Buffer? Using C#

I am trying to use Google protocol buffer library for serializing and deserialzing process in C#. I can deserialize using following codeNotificationSet.Parser.ParseJson(json); And this is working fine.
NotificationSet is auto generated file by .proto.
But here you can see it is not generic. So, instead of specif type i need to make a method in generic way. Can you please advice on this?
Example:
public async Task<TResult> Deserialize<TResult, TValue>(TValue value)
{
TResult.Parser.ParseJson(value.ToString());
}
Problem is TResult is generic type, so unable to get Parser method from that.
Found an answer.
Try with is code to achieve generic deserialization process using google protocol buffer library.
public async Task<TResult> Deserialize<TResult,TValue>(TValue value)
{
try
{
System.Type type = typeof(TResult);
var typ = Assembly.GetExecutingAssembly().GetTypes().First(t => t.Name == type.Name);
var descriptor = (MessageDescriptor)typ.GetProperty("Descriptor", BindingFlags.Public | BindingFlags.Static).GetValue(null, null);
var response = descriptor.Parser.ParseJson(value.ToString());
return await Task.FromResult((TResult)response);
}
catch (Exception ex)
{
throw ex;
}
}
}

Using Enterpise Library 6 Exception Handling Application Block with WCF?

I have these three packages loaded to my WCF service project:
EnterpriseLibrary.Common Version 6.0.1304.0
EnterpriseLibrary.ExceptionHandling 6.0.1304.0
EnterpriseLibrary.ExceptionHandling.WCF Version 6.0.1304.0
Here is the service interface and MyTestFault DataContract:
[ServiceContract]
public interface IRepairService
{
[OperationContract]
[FaultContract(typeof(MyTestFault))]
string SaveRepairCode(string failureCode, string description);
}
[DataContract]
public class MyTestFault
{
#region Member Fields
private string _message = "An unexpected error occured while executing the service method.";
#endregion
#region Properties
[DataMember]
public string Message
{
get { return _message; }
set { _message = value; }
}
#endregion
#region Constructor(s)
public MyTestFault() { }
#endregion
}
Here is the implementation of the service:
[ExceptionShielding("TestPolicy")]
public class RepairService : IRepairService
{
#region Private members
private WimDAL wimDAL;
ExceptionManager exManager;
#endregion
#region Constructor(s)
public RepairService()
{
wimDAL = new WimDAL();
var testPolicy = new List<ExceptionPolicyEntry>
{
{
new ExceptionPolicyEntry(
typeof(SqlException),
PostHandlingAction.ThrowNewException,
new IExceptionHandler[]
{
new FaultContractExceptionHandler(
typeof(MyTestFault),
"SqlException Occurred.",
new NameValueCollection(){ { "Message", "Message" }})
})
},
{
new ExceptionPolicyEntry(
typeof(Exception),
PostHandlingAction.ThrowNewException,
new IExceptionHandler[]
{
new FaultContractExceptionHandler(
typeof(MyTestFault),
"Exception Occurred.",
new NameValueCollection(){ { "Message", "Message" }})
})
}
};
var policies = new List<ExceptionPolicyDefinition>();
policies.Add(new ExceptionPolicyDefinition(
"TestPolicy", testPolicy));
exManager = new ExceptionManager(policies);
}
#endregion
/// <summary>
/// Insert a new fail code with description into RPCODE.
/// Duplicate primary key will throw SqlException that should be processed by EHAB
/// </summary>
public string SaveRepairCode(string failureCode, string description)
{
using (TransactionScope txScope = new TransactionScope())
{
WimSQLCommand sc = new WimSQLCommand() { StoredProcedure = "Repair.RPCODE_Insert" };
sc.Parameters.Add(new SqlParameter("#FailureCode", failureCode));
sc.Parameters.Add(new SqlParameter("#Desc", description));
exManager.Process(() => wimDAL.Execute_NonQueryNoReturn(sc), "TestPolicy");
txScope.Complete();
return "<Save_Repair_Code></Save_Repair_Code>";
}
}
}
Now, I have a TestClient console application that is part of the same project that has a reference to the project and a service reference. From there I call the SaveRepairCode() method and try to catch the specific fault exception like so:
ServiceReference1.RepairServiceClient r = new ServiceReference1.RepairServiceClient();
Console.WriteLine("Enter a new repair code:");
string repairCode = Console.ReadLine();
Console.WriteLine("Enter description:");
string description = Console.ReadLine();
try
{
r.SaveRepairCode(repairCode, description);
}
catch (FaultException<MyTestFault> ex)
{
//do something
throw;
}
catch (FaultException fex)
{
//do something
throw;
}
Finally, I run the console app and try to save a duplicate repair code. I know through debugging that this causes the SqlException to occur. After I step over the SqlException, I see the "FaultContractWrapperException was unhandled by user code" exception and it has the message I specified in the policy of "SqlException occurred.". When I step over that I get back to the client and see this error:
CommunicationException was unhandled
The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error.
PS - this is Enterprise Library 6 with WCF and I made no manual changes to the web.config... and yes, includeExceptionDetailInFaults is set to false.
What am I missing here? Thanks in advance.
UPDATE
Looks like I was missing this one line of code after instantiating the new ExceptionManager.
ExceptionPolicy.SetExceptionManager(exManager);
Nice to see that this one line of code is NOT in the Enterprise Library 6 - April 2013.chm but it IS in the "Developer's Guide to Microsoft Enterprise Library-Preview.pdf" on page 90 of 269. After including that one line I get into the proper FaultException catch on the client.
With that being said, I still can't get other MyTestFault properties on the client. For example, if I add public string StoredProcedureName to MyTestFault and map it to the SqlException's "Procedure" property, I always see null on the client. The only change in the policy for this would be to add the mapping like so:
new NameValueCollection(){ { "Message", "{Message}" }, { "StoredProcedureName", "{Procedure}" } }
It turns out this line was the culprit.
exManager.Process(() => wimDAL.Execute_NonQueryNoReturn(sc), "TestPolicy");
Insead of using the ExceptionManager's Process method, just execute the command you expect a potential exception for like so.
wimDAL.Execute_NonQueryNoReturn(sc);
This does not follow what the "Developer's Guide to Microsoft Enterprise Library-Preview.pdf" says but I guess the documentation is still a work in progress. I hope this helps someone else.

Store and retrieve string arrays in HBase

I've read this answer (How to store complex objects into hadoop Hbase?) regarding the storing of string arrays with HBase.
There it is said to use the ArrayWritable Class to serialize the array. With WritableUtils.toByteArray(Writable ... writable) I'll get a byte[] which I can store in HBase.
When I now try to retrieve the rows again, I get a byte[] which I have somehow to transform back again into an ArrayWritable.
But I don't find a way to do this. Maybe you know an answer or am I doing fundamentally wrong serializing my String[]?
You may apply the following method to get back the ArrayWritable (taken from my earlier answer, see here) .
public static <T extends Writable> T asWritable(byte[] bytes, Class<T> clazz)
throws IOException {
T result = null;
DataInputStream dataIn = null;
try {
result = clazz.newInstance();
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
dataIn = new DataInputStream(in);
result.readFields(dataIn);
}
catch (InstantiationException e) {
// should not happen
assert false;
}
catch (IllegalAccessException e) {
// should not happen
assert false;
}
finally {
IOUtils.closeQuietly(dataIn);
}
return result;
}
This method just deserializes the byte array to the correct object type, based on the provided class type token.
E.g:
Let's assume you have a custom ArrayWritable:
public class TextArrayWritable extends ArrayWritable {
public TextArrayWritable() {
super(Text.class);
}
}
Now you issue a single HBase get:
...
Get get = new Get(row);
Result result = htable.get(get);
byte[] value = result.getValue(family, qualifier);
TextArrayWritable tawReturned = asWritable(value, TextArrayWritable.class);
Text[] texts = (Text[]) tawReturned.toArray();
for (Text t : texts) {
System.out.print(t + " ");
}
...
Note:
You may have already found the readCompressedStringArray() and writeCompressedStringArray() methods in WritableUtils
which seem to be suitable if you have your own String array-backed Writable class.
Before using them, I'd warn you that these can cause serious performance hit due to
the overhead caused by the gzip compression/decompression.

How to properly handle WCF faults with Silverlight?

No matter how hard I try I cannot seem to be able to handle WCF faults in Silverlight.
In fact the error seems to never leave the server !
E.g. when I debug it, it stops on the line where I throw the FaultException saying it was not handled:
[SilverlightFaultBehavior]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class StoreService : IStoreContract
{
public System.Collections.Generic.List<string> GetStoreDesignNames()
{
try
{
StoreDataContext swdc = new StoreDataContext();
var query = from storeDesign in swdc.StoreDesignDBs select storeDesign.Name;
return query.ToList();
}
catch (System.Data.SqlClient.SqlException sqlExcept)
{
throw new FaultException<SqlFault>(new SqlFault() { Message = sqlExcept.Message });
}
}
}
The class that implements this method derives from a contract interface:
[ServiceContract(Namespace = "Store")]
public interface IStoreContract
{
/// <summary>
/// Obtain the list of store design names.
/// </summary>
[OperationContract,
FaultContract(typeof(SqlFault))]
List<String> GetStoreDesignNames();
}
And the SqlFault class is defined like this:
public class SqlFault
{
public String Message { get; set; }
}
On the client side I handle the error as follow:
// swc is the client
swc.GetStoreDesignNamesCompleted += new EventHandler<ServiceReference.GetStoreDesignNamesCompletedEventArgs>((obj, evt) =>
{
if (evt.Error == null)
{
// In case of success
MessageBox.Show(evt.Result.First());
}
else if (evt.Error is FaultException<ServiceReference.SqlFault>)
{
FaultException<ServiceReference.SqlFault> fault = evt.Error as FaultException<ServiceReference.SqlFault>;
Dispatcher.BeginInvoke(() =>
{
ErrorWindow ew = new ErrorWindow(fault.Detail.Message, "No details");
ew.Show();
});
}
});
swc.GetStoreDesignNamesAsync();
I have tried to put the [SilverlightFaultBehavior] attribute on the interface, to no avail. Even if I do without the interface I still have this error.
I have also tried to use a behavior extension in the web.config as described here but I get a warning saying the extension is not valid.
How does one go about properly handling WCF fault in Siverlight ?
Thanks in advance.
I haven't used WCF (been using WCF RIA Services) but I did come across this article a while ago.
Getting something better than “Server not found.” from WCF in Silverlight
After battling with this for hours I finally hacked something together that works.
This is really a horrible hack and I would have much preferred to use BehaviorExtension for this task. The trick is to set manually the HTTP status code in the body of the WCF method like so:
public System.Collections.Generic.List<string> GetStoreDesignNames()
{
try
{
StoreDataContext swdc = new StoreDataContext();
var query = from storeDesign in swdc.StoreDesignDBs select storeDesign.Name;
return query.ToList();
}
catch (System.Data.SqlClient.SqlException sqlExcept)
{
System.ServiceModel.Web.WebOperationContext ctx = System.ServiceModel.Web.WebOperationContext.Current;
ctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;
throw new FaultException<SqlFault>(new SqlFault() { Message = sqlExcept.Message });
}
}
The error message then correctly displays on the client side.
If anybody has a better solution than this I'd like to hear it.