wcf - System.Exception.Data will not serialise on DataContract? -
i have wcf services using datacontracts , wanted hoping pass exception custom dictionary< string , object > data in data property, when add data on array before throwing following error in errorhandler of custom servicebehavior:
type 'system.collections.listdictionaryinternal'
with data contract name 'arrayofkeyvalueofanytypeanytype:http://schemas.microsoft.com/2003/10/serialization/arrays' not expected. add types not known statically list of known types - example, using knowntypeattribute attribute or adding them list of known types passed datacontractserializer.
do invariably need create custom exception dictionary property annotated datacontract , throw that? idea of using errorhandler avoiding handle exceptions in each service method, still need add further annotations methods? missing?
for reference, faulterrorhandler class:
public class faulterrorhandler : behaviorextensionelement, ierrorhandler, iservicebehavior { public bool handleerror(exception error) { if (!logger.isloggingenabled()) return true; var logentry = new logentry { eventid = 100, severity = traceeventtype.error, priority = 1, title = "wcf failure", message = string.format("error occurred: {0}", error) }; logentry.categories.add("middletier"); logger.write(logentry); return true; } public void providefault(exception error, system.servicemodel.channels.messageversion version, ref system.servicemodel.channels.message fault) { var faultexception = new faultexception<exception>( error, new faultreason(string.format("system error occurred, exception: {0}", error))); var faultmessage = faultexception.createmessagefault(); fault = message.createmessage(version, faultmessage, schema.webservicestandard); } public void addbindingparameters(servicedescription servicedescription, system.servicemodel.servicehostbase servicehostbase, system.collections.objectmodel.collection<serviceendpoint> endpoints, system.servicemodel.channels.bindingparametercollection bindingparameters) { } public void applydispatchbehavior(servicedescription servicedescription, system.servicemodel.servicehostbase servicehostbase) { foreach (channeldispatcher chandisp in servicehostbase.channeldispatchers) { chandisp.errorhandlers.add(this); }; } public void validate(servicedescription servicedescription, system.servicemodel.servicehostbase servicehostbase) { } public override type behaviortype { { return typeof(faulterrorhandler); } } protected override object createbehavior() { return new faulterrorhandler(); } }
my typical service interface looks like:
[servicecontract(name = "service", namespace = schema.webservicestandard, sessionmode = sessionmode.allowed)] public interface iservice { [operationcontract(name = "getsomething")] [faultcontract(typeof(validationfault))] lookupresult getsomething(); }
system.exception implements iserializable, handled serializer same way dictionary - can [de]serialized, need tell serializer types going [de]serialized. in case of exception, can't change class declaration, if want make scenario work, you'll need add known types in service contract (using [serviceknowntype]) both class used data property (which uses internal type system.collections.listdictionaryinternal
) , types you'll add data dictionary. code below shows how can done (although i'd advice against that, should define dto types handle information needs returned, prevent having deal internal implementation details of exception class.
public class stackoverflow_6552443 { [datacontract] [knowntype("getknowntypes")] public class mydcwithexception { [datamember] public exception myexception; public static mydcwithexception getinstance() { mydcwithexception result = new mydcwithexception(); result.myexception = new argumentexception("invalid value"); result.myexception.data["somedata"] = new dictionary<string, object> { { "one", 1 }, { "two", 2 }, { "three", 3 }, }; return result; } public static type[] getknowntypes() { list<type> result = new list<type>(); result.add(typeof(argumentexception)); result.add(typeof(dictionary<string, object>)); result.add(typeof(idictionary).assembly.gettype("system.collections.listdictionaryinternal")); return result.toarray(); } } [servicecontract] public interface itest { [operationcontract] mydcwithexception getdcwithexception(); } public class service : itest { public mydcwithexception getdcwithexception() { return mydcwithexception.getinstance(); } } public static void test() { string baseaddress = "http://" + environment.machinename + ":8000/service"; servicehost host = new servicehost(typeof(service), new uri(baseaddress)); host.addserviceendpoint(typeof(itest), new basichttpbinding(), ""); host.open(); console.writeline("host opened"); channelfactory<itest> factory = new channelfactory<itest>(new basichttpbinding(), new endpointaddress(baseaddress)); itest proxy = factory.createchannel(); console.writeline(proxy.getdcwithexception()); ((iclientchannel)proxy).close(); factory.close(); console.write("press enter close host"); console.readline(); host.close(); } }
Comments
Post a Comment