This evening I played with Indigo and WS-AT, to see if it works, in order to use it in a project of a customer of mine.
First of all the good news: it works :-) as it did in PDC03 bits! Great job guys!
Second news: it's not so easy to manage all the stuff, but at least it works fine.
I developed two different services, working on a couple of SQL Server 2005 database.
One service is exposed using a net.tcp (netProfileTcpBinding) binding. The other is exposed using http (wsProfileBinding), self-hosted.
Both are used by a third party client, that covers the transactional work with a TransactionScope.
Here is a sample of one of the two transactional services:
namespace ServiceOne
{
[ServiceContract(
FormatMode=ContractFormatMode.XmlFormatter,
Namespace="http://schemas.devleap.com/Services/OrderService1",
Style=ServiceOperationStyle.DocumentBare,
Use=ServiceOperationBindingUse.Literal)]
[BindingRequirements(
TransactionFlowRequirements = RequirementsMode.Require)]
public interface ITxServiceOne
{
[OperationContract(
Action="urn:saveOrder1")]
Int32 SaveOrder(OrdersLibrary.Order order);
}
[ServiceBehavior(
AllowConcurrentTransactions=true,
TransactionIsolationLevel=IsolationLevel.ReadCommitted)]
public class TxServiceOne: ITxServiceOne
{
[OperationBehaviorAttribute(
AutoEnlistTransaction = true,
AutoCompleteTransaction = true)]
public int SaveOrder(OrdersLibrary.Order order)
{
OrdersLibrary.OrderBiz ob = new OrdersLibrary.OrderBiz();
return (ob.SaveOrder(order));
}
}
}
Take care of BindingRequirements and OperationBehavior attributes, respectively on the service contract and on the operation implementation.
Here is the service side configuration file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<appSettings>
<add key="SqlConnectionString" value="..."/>
</appSettings>
<system.serviceModel>
<services>
<service
serviceType="ServiceOne.TxServiceOne, ServiceOne"
behaviorConfiguration="txServiceBehavior">
<endpoint
contractType="ServiceOne.ITxServiceOne, ServiceOne"
address="http://localhost:35000/TxServiceOne.svc"
bindingConfiguration="txBinding"
bindingSectionName="wsProfileBinding" />
</service>
</services>
<bindings>
<wsProfileBinding>
<binding configurationName="txBinding" flowTransactions="Required" />
</wsProfileBinding>
</bindings>
<behaviors>
<behavior
configurationName="txServiceBehavior"
returnUnknownExceptionsAsFaults="true" >
</behavior>
</behaviors>
</system.serviceModel>
</configuration>
Pay attention to the behaviors section, where I declare to manage any exception as a Fault.
Take a look also at the custom binding configuration, defined in order to require transactions.
The other service is very similar to the first one.
Lastly here is the main part of client code:
schemas.devleap.com.EntitiesOrder.Order order = new schemas.devleap.com.EntitiesOrder.Order();
order.id = 10;
order.description = "Order 10";
TransactionOptions options = new TransactionOptions();
options.IsolationLevel = IsolationLevel.ReadCommitted;
options.Timeout = TimeSpan.FromSeconds(30);
using(TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, options))
{
TxServiceOneProxy svcOne = null;
TxServiceTwoProxy svcTwo = null;
try
{
// External transactional activity
svcOne = new TxServiceOneProxy();
Console.WriteLine("Service One: {0}", svcOne.SaveOrder(order));
try
{
// Internal transactional activity
svcTwo = new TxServiceTwoProxy();
Console.WriteLine("Service Two: {0}", svcTwo.SaveOrder(order));
// Transaction commit, in case of success
scope.Complete();
}
finally
{
// Internal channel closing
svcTwo.Close();
}
}
finally
{
// External channel closing
svcOne.Close();
}
}
Here you can find all the code of the demo solution I developed to test WS-AT support in Indigo.
In order to make it work, don't forget to download this fix (published on 21/06/2005):
http://www.microsoft.com/downloads/details.aspx?familyid=32187993-4736-4a06-97c7-1282b67e3137&displaylang=en
I hope you'll enjoy your Indigo transactional experience :-) !
Yesterday I was involved in working with dynamic generic types for a project I'm working on. At least I achieved this solution to dinamically create a Generic Type for instance reading a .config file:
using System;
using System.Collections.Generic;
using System.Text;
namespace DynamicGeneric
{
class Program
{
static void Main(string[] args)
{
// "Standard" generic instantiation
GenericClass<PaoloEntity> paoloGenericClass = new GenericClass<PaoloEntity>();
Console.WriteLine(paoloGenericClass.GetEntity());
// Create a parametric generic type instance
Type paoloEntityType = Type.GetType("DynamicGeneric.PaoloEntity, DynamicGeneric");
Type paoloGenericClassType = typeof(GenericClass<>).MakeGenericType(paoloEntityType);
Object paoloGenericClassDynamic = Activator.CreateInstance(paoloGenericClassType);
Console.WriteLine(paoloGenericClassDynamic.ToString());
GenericClass<PaoloEntity> paoloGenericClassDynamic2 = (GenericClass<PaoloEntity>)paoloGenericClassDynamic;
Console.WriteLine(paoloGenericClassDynamic2.GetEntity());
}
}
public class BaseEntity
{
private String _name;
public String Name
{
get { return(this._name); }
set { this._name = value; }
}
}
public class PaoloEntity: BaseEntity
{
public PaoloEntity()
{
this.Name = "Paolo";
}
public override string ToString()
{
return (String.Format("Entity: {0}", this.Name));
}
}
public class GenericClass<TEntity>
where TEntity : BaseEntity, new()
{
public TEntity GetEntity()
{
return (new TEntity());
}
}
}
The only last problem I'm facing on is the ability not only to create an instance but also to declare a Generic Type dinamically. I mean something like:
GenericClass<typeof(paoloGenericClassType)> paoloGenericClassDynamic = ....
Of course the above line does not compile, because the compiler needs to know the generic parameter type provided to the Generic Type called "GenericClass" (I guess). On the other side I don't want to declare my Generic Type instance as an Object ... I'd loose all the benefits of generics ..... Any idea?
Update: of course I know that I can use a base class or interface for my GenericClass, in order to have a common signature for my GetEntity method instead of having just an Object. The problem that I've in my real application (not in the snippet published here) is that my GenericClass (that in reality are many classes) have a base interface that is based on generics too... probably I'm wondering too much from my life! :-)