Showing posts with label EntLib. Show all posts
Showing posts with label EntLib. Show all posts

Wednesday, April 30, 2008

EntLib3 Replace Handler, ExceptionHandlingException

Using the Enterprise Library 3 exception replace handler can help you handle e.g. WCF FaultException<T> on the client and replace it with your own exception derived from ApplicationException. This will shield your client app from the different types of FaultException<T> where T: FaultContract types defined in the WSDL as wsdl:fault schemas and provide a normalized application exception type. This client-side exception shielding mechanism ensures that the proxy fault types need not be exposed outside your service agent.

There is one exception best practice to remember to implement for the @replaceExceptionType configuration to work: your derived exception must implement the three recommended constructors default, message, message and inner exception. If you forget, the entlib HandleException call will throw an "unable to handle exception" ExceptionHandlingException error.

Note the [[fault contract type]] syntax to be able to specify handlers for generic exceptions:

<add type="System.ServiceModel.FaultException`1[[MyServiceAgent.Proxy.GetCustomerListFault, MyServiceAgent.Proxy, Version=1.0.0.0]], System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
postHandlingAction="ThrowNewException" name="MyApplicationException">


You have to edit the .config file manually as the EntLib3 editor does not support generics

Wednesday, April 16, 2008

WCF: Client Domain Objects, Decorator Pattern

The client domain objects (aka business entity - BE) must be related to the data contracts provided by the web-services. Still, they will need to be enhanced with e.g. dirty-tracking, validation, state, property conversions (xs:date), business rules, and other aspects needed to produce a fully working client application. This article describes how to achieve this when sharing domain objects across layers is not an option (i.e. interop with JEE services), and the same applies to AOP.

One option for implementing the BE objects, described in this article, is to apply the Decorator pattern to the WSDL scema-based DTO objects to enhance them into full-fledged domain objects. Read ‘
Design of Client Domain Objects’ for an intro this option and the related Mapper option.

If you do not like this Decorator option due to the weak [XML attribute] link to the data contracts (see end of article), you can always use a derived decorator class instead of a partial class. Make all your BE enhancements in the derived class using a combination of DTO overrides and new domain logic. If you prefer explicit, debuggable code, you're better off using the Mapper option.

Service Proxy

Use the SVCUTIL.EXE /REFERENCE switch when generating the proxy code and messages to reuse your BE objects as DTOs and to avoid getting new, duplicate DTO objects generated (might not compile due to name clashes). Alternatively, just remove the DTO code from the generated proxy. Make sure that the proxy code reference the .NET namespace and interface assembly that contains your BE objects.

Business Entities

You can use the data contract DTO objects generated by SVCTIL.EXE /DCONLY to get started. This will give you data-binding enabled (/EDB) anemic entity objects with all the properties in place, annotated with XML serialization attributes. Just ensure that the output files from SVCUTIL.EXE do not overwrite your code. The DTO objects become your generated BE objects - ready for decoration.

The BE objects must be manually maintained whenever you make changes to the generated BE code, e.g. to add EntLib3 validation attributes on the properties. Keep your additions to the generated BE in a partial class as far as possible, e.g. add new properties and methods in a partial class extending the decorated class. If all your decorator code can be isolated into a partial class, then the generated BE code can be re-generated without losing your extended BE code.

Our programming model for decorator-based client domain objects is based on using two partial classes; one T.schema.cs class file for all code based originally on the data contracts, and one T.cs class file for all added aspects. T is the type name of the BE.

Note that BE constructors will not be called during deserialization. Create a method to be used as a surrogate constructor to be run after deserialization and mark it with [OnDeserialized]. This is a good place for resetting e.g. the dirty flag:

[OnDeserialized]
void DeserializationCtor(StreamingContext context)
{
_isDirty = false;
}

Your BE class must still have a constructor to initialize the object for normal use. The constructor must initialize all properties that must have a defined initial value. In addition, the c'tor must initialize all child objects that are exposed as (de-normalized) public properties, to avoid null reference exceptions when using the BE (make it simple to use the BE). This also applies to child collections; create the collection to make it ready for use.

public NominationType()
{
//NOTE: WILL NOT BE CALLED ON DE-SERIALIZATION
//initialize all normalized valueobjects with members
this.NominatedValueField = new UnitValueType();
this.NominatedValueField.Unit = String.Empty;
}

Also initialize all fields that are required by the XSD schema, failure to initialize these fields will give serialization errors:
[DataMemberAttribute(IsRequired=true, . . .) ]

Don't break the DRY principle by adding the value object initialization code multiple places.

Dirty Tracking

If your BE implements INotifyPropertyChanged to enable data-binding, then the event is a good place to add dirty-tracking: Simple Dirty Tracking in Domain Objects

Converting XML Data Types to/from Strongly Typed Properties

Note that xs:date becomes string in .NET as there is no Date only type, just DateTime. Do not let this kind of weak type design leak into your BE objects. Contain the weak typing inside your BE object by converting to/from strongly typed properties.

private string _demandDateData; //XML xs:date datatype

public DateTime DemandDate
{
get
{
return DateTime.ParseExact(this._demandDateData, WSDateFormat, null);
}
set
{
string xsDate = value.ToString(WSDateFormat);
if (this._demandDateData.Equals(xsDate) != true)
{
this._demandDateData = xsDate;
this.RaisePropertyChanged("DemandDate");
}
}
}

This keeps your BE object within the "Simple vs Easy" principle.

De-normalization of BE Value Objects

The data contracts provided by the web-services will most likely contain some DDD value objects for numeric types annotated with some related attributes (e.g. money with currency) and other similar cases. These value objects will become child objects of the BE object, which is not very data-binding friendly as most controls (grids, etc) needs the data to be non-nested properties of the bound object. In addition, one control can only have one binding source. Thus, unlike master-details type binding that can be resolved using multiple binding sources, nested value objects must be de-normalized and projected as normal properties directly on the BE objects.

Start by making the value object private and give the property a new name (e.g. suffix with Data) while specifying the original name in the serialization attribute to keep the link to the XML. Keep the RaisePropertyChanged parameter equal to the property name.

[DataMemberAttribute(Name = "NominatedValue", IsRequired = true, EmitDefaultValue = false, Order = 2)]
private UnitValueType NominatedValueData
{
get { return this.NominatedValueField; }
set { . . . }
}

Then create the de-normalized public properties (in a partial class) as required by the BE and data-binding needs. The new public properties should be wrappers exposing an element of the original private member value object, using a friendly name and the correct data type. Make sure that the new-old value comparison is correct. Keep the RaisePropertyChanged parameter equal to the new property name.

public Decimal NominatedValue
{
get { return this.NominatedValueField.Value; }
set
{
if (this.NominatedValueField.Value.Equals(value) != true)
{
this.NominatedValueField.Value = value;
this.RaisePropertyChanged("NominatedValue");
}
}
}

public string NominatedValueUnit
{
get { return this.NominatedValueField.Unit; }
set { . . . this.RaisePropertyChanged("NominatedValueUnit"); }
}

As can be seen from the example, the new public properties are named by concatenating the value object name and the exposed property name; except for when the property name is just repeating the last part of the value object (i.e. NominatedValue.Value).

Remember to initialize all the value object children in the BE c'tor; both create the child objects and set their initial values.

Keeping the BE Synchronized with the Data-Contract Schema

It is imperative that the XML serialization attributes in code are correct according to the data contract XSD when using the decorator approach on proxy DTO objects to implement BE objects. There are three typical changes that can break the mapping between the BE code and the payload XML:

  • Changes to the code by renaming properties without updating the XML serialization attributes accordingly
  • Changes to the data contract XSD schema without adding properties with correct XML serialization attributes
  • Changes to the data contract XSD schema without updating the XML serialization attributes accordingly
The first issue can happen when e.g. re-exposing a property by renaming and hiding the original property (such as for de-normalizing a value object). This will require updating the XML serialization attribute to keep the mapping of the code to XSD correct:

[DataMemberAttribute(Name = "NominatedValue", . . .) ]
private UnitValueType NominatedValueData

The next two issues are caused by adding new items to the data contract or changing some existing items. The latter is not recommended and is definitively not a recommended practice for published contracts:

  • It is a proven practice that published contracts are not changed, except for non-breaking changes in minor versions.
  • For new, non-breaking versions of the contract, items must only be added at the end of the existing contract.
When a new minor version of a published data contract must be incorporated into your BE class, then start by adding the properties to hold the new data items, then add the applicable XML serialization attributes with the correct sequence order value:

[DataMemberAttribute(. . . , Order=<order number in XML xs:sequence element for item>) ]

For new major versions of data contracts, you must consider creating a new version of the BE class in a new .NET namespace. This allows you to do controlled versioning of your domain objects in synchronization with the versioning policy of the service contracts.

However, during the development of the web-services, the contracts are bound to get breaking changes as the data contracts evolve (which is OK as they are still not published). For this reason, wait as long as you can to make changes to the generated BE code, stick to working on the partial class used to decorate the BE. This will allow you to re-generate the schema-bound parts of your BE to keep up with the changes in the data contracts.


A side note: deriving your BE objects from the DTO objects is an alternative to partial classes that strictly enforces the separation of decorator code from generated code, and allows the generated code to be auto-generated over and over again - like for the Mapper option. Alas, there are drawbacks to inheriting the DTOs also, as none of the generated proxy artifacts are geared towards this. Look into using an AOP framework to do dynamic subclassing if chosing to derive your BE objects.

For data contracts under development, any combination of adding, changing, removing and reordering of data contract items can be expected to occur. The XML serialization attributes must then be updated accordingly.

Thursday, May 10, 2007

WCF+EntLib3: Getting started

In addition to the WCF+EntLib3 validation and exception handling posts at Guy Burstein's blog/CodeProject, this info from David Hayden's blog about logging should get you started:
  • A new EntLibLoggingProxyTraceListener class. This trace listener is designed to be used in WCF’s System.ServiceModel trace source, which is configured within the <system.diagnostics> section. This trace listener receives WCF messages logged to this trace source, wraps them in an XmlLogEntry class, and forward them to the Logging Application Block where it can be processed according to the application block configuration.
  • A new XmlLogEntry class, which derives from LogEntry but includes a new Xml property that preserves the original XML data provided by WCF.
  • A new XmlTraceListener class, which derives from the .NET XmlWriterTextWriter class. This class can extract XML data from an XmlLogEntry class
In short, attributes and the interceptor mechanisms of WCF are used to integrate EntLib3 features for validation and exception handling, while logging is just another trace listener. You'll need to understand how to configure all three application blocks to make the WCF integration work. I recommend using the EntLibConfig.exe tool to configure the EntLib3 stuff, and the SvcConfigEditor.exe tool to configure WCF tracing wrt logging. The WCF toolbox is included in the .NET3 SDK.

That is all I have managed to find regarding the WCF features of EntLib3. The online MSDN docs contains mostly "new WCF features added to the ____ Application Block" statements and no code samples.

Monday, May 07, 2007

WCF: Exception Handling with Logging

In my 'WCF Exception Shielding using Generics' post there was a "//TODO: add logging as applicable" comment, which I now have implemented using the EntLib3 Logging Application Block.

As part of the error information I wanted to write to the Windows Application Event Log was the actual request message causing the service operation exception. Thus, I googled for a solution for how to get the XML of the incoming message, so that I could log it along with the stack trace. There are a lot of options for getting at the message in WCF:

The problem of the first option is that I only want to get at the message XML when handling exceptions. The second option is not an option (duh!) as I want my operations to be strongly typed using my data contracts. The third option was more like what I wanted, but it seemed to be unneccessary complicated code.

The code to get at the message XML from within an operation is quite simple:

private static string GetMessageXml(DefaultMessage request)
{
return OperationContext.Current. RequestContext.RequestMessage.ToString();
}

This approach does not work for operations with no RequestContext, such as one-way operations.

The logging code is added after creating the fault details, this makes it possible to use fault details data in the log. This is how my WCF exception shielding with logging looks like:

public static FaultException<T> NewFaultException<T>(Exception ex)
where T : FaultContracts.DefaultFaultContract, new()
{
return NewFaultException<T>(ex, null);
}

public static FaultException<T> NewFaultException<T>(Exception ex, DefaultMessage request)
where T : FaultContracts.DefaultFaultContract, new()
{
return CreateNewFaultException<T>(ex, request);
}

private static FaultException<T> CreateNewFaultException<T>(Exception ex, DefaultMessage request)
where T : FaultContracts.DefaultFaultContract, new()
{
StackFrame stackFrame = new StackFrame(2);
string methodName = stackFrame.GetMethod().Name;

T fault = new T();
Type type = fault.GetType();
type.InvokeMember("SetFaultDetails", BindingFlags.Public BindingFlags.Instance BindingFlags.InvokeMethod, null, fault, new object[] { ex });

string msg = String.Format("An unexpected error occurred in {0}.", methodName);
Dictionary<string, object> props = new Dictionary<string, object>();
props.Add("stackTrace", ex.ToString());
if(request!=null)
{
string xml = GetMessageXml(request);
props.Add("requestMessage", xml);
}
Logger.Write(msg, Category.General, Priority.Highest, (int)EventLogId.Exception, TraceEventType.Error, ex.Message, props);

string reasonText = methodName + " failed, check detailed fault information.";

#if DEBUG
reasonText = methodName + " error: " + ex.ToString();
#endif

return new FaultException<T>(fault, new FaultReason(reasonText));
}

Note that I now use an inner private method to create the new fault to be thrown and thus must skip two stack frames to get the details of the original method called. The DEBUG section is there to make it simple to see full exception details in NUnit or with Fiddler when debugging the service. This DEBUG code must never make it into release builds, as this is not exactly exception shielding.
I have not looked into the WCF app-blocks integration mechanisms added in the april release of EntLib3, that is next on my task list for quieter days. There is not much info about this to be found, but Guy Burstein provides some samples. Btw, you should check out the Patterns and Practices Guidance site, it contains useful stuff and tutorials about EntLib3.

Sunday, May 06, 2007

EntLib3 should apply convention over configuration

After using the EntLib3 validation application block (VAB) for a while now, and also some of the new configuration mechanisms such as external configuration source and environmental overrides for different build types; it occurs to me that there is a bit to much XML noise in the config.

EntLib3 should do as in Castle Windsor and MonoRail and Ruby on Rails; apply "convention over configuration". In EntLib3 config files, you have to add mandatory attributes to identify the default configuration when there are multiple config options. Using "first is default" as in the Windsor 'constructor injection' mechanism would make configuration simpler and less error prone (see VAB issue below). I understand the reasons for having a default-identifier as a separate attribute, but with the new config override and merging mechanisms in EntLib3, there should be less need for compulsory config "switching" attributes.

The convention "first is default" would prevent silly omission errors such as not setting the default rule set in VAB less drastic. As it is now, if you forget to set the VAB default rule set, no validation will be applied, neither will there be any "no rules" exception - and your code will run as if all validations passed, even if there are plenty of broken rules in the input.

While I'm at it, the caching of connection strings and service URLs in the Settings class and the service proxies, is also really silly; you will not be able to detect that some configuration is missing until you move the solution to an isolated staging environment that has no access to the databases/service resources referenced in the development environment. Most test environments are not that isolated from the development environment, and such config errors can go undetected for a long time during testing. This is one area where it would be better if Microsoft could make configuration compulsory.

Tuesday, April 10, 2007

EntLib3 April 2007: still some VAB issues

It's been quiet around here the last month, as I've been "busy" finishing the March sprint of our current project - after skiing in Avoriaz, France for one week first. Today I'm back after a one week Easter vacation, skiing in Trysil, Norway.

The production version of EntLib 3 was released last week, and I have downloaded it and tested the validation application block with our WCF services. The first thing I noticed when recompiling was that a breaking change has been introduced in EntLib3 April 2007: the attribute parameters for specifying a custom validation message are gone from the attribute constructors. You now need to use named parameters to specify your message in a VAB attribute, e.g. MessageTemplate = "message" as shown here:

[RegexValidator(@"^.*$", RegexOptions.IgnoreCase, MessageTemplate = "Invalid ticket")]

When my code again compiled, I checked if some of the issues I've reported in the February CTP had been fixed. The most serious issue for my current project is validating recursive object collections, e.g. a structure of folders that can contain files and sub-folders.

The [ObjectCollectionValidator] issue has not been fixed, the NUnit tests still silently fails - caused by a stack overflow due to an infinite loop when building the validator tree for the recursive object structure.

The second issue is that the [IgnoreNulls] attribute should get a sibling [IgnoreNullOrEmpty] attribute for strings. This is especially important for validating WCF messages and data contracts; if an optional string element is not specified (null) in the message on-the-wire, the DataContractSerializer will deserialize the missing string element by applying the default value for strings: String.Empty. So, now the null value sent by the client is actually String.Empty when applying the validation rules on the server, and thus the [IgnoreNulls] rule is not sufficient for easily validating WCF messages.

Specifying a set of validation attributes to build a ruleset for covering "ignore if null or empty, otherwise string must be 5-10 chars long" using the [ValidatorComposition] attribute is not simple, thus I have logged the need for [IgnoreNullOrEmpty] as an issue.