Hi All,
Sorry if this is a n00b thing to ask - I've only been into DotNet/C#
for about two weeks.
But basicly what I am trying to do is expose DAO's throught WCF
services.
The problem is when I try to call the Service from the client I get
the following exception : Test method
jTekPos.Client.RemoteProxy.Tests.UserProxy_Fixture.Can_We_Lookup_A_Member
threw exception: System.ServiceModel.FaultException`1
[System.ServiceModel.ExceptionDetail]: No persister for: User.
I believe ( from what I have googled ) that it has something to do
with the Serializer not serializing the references properly, But I
have spent way to long googling and really need some help now.
My User.cs is defined here :
[code]
namespace jTekPos.Data.Model
{
[Serializable]
[DataContract]
[ActiveRecord("usrs")]
public class User : ActiveRecordBase<User>
{
[DataMember]
[PrimaryKey("user_id")]
public int UserId { get; set; }
[DataMember]
[Property("user_name")]
public String Username { get; set; }
[DataMember]
[Property("pass_word")]
public String Password { get; set; }
[DataMember]
[Property("firstname")]
public String Firstname { get; set; }
[DataMember]
[Property("surname")]
public String Surname { get; set; }
[DataMember]
[HasAndBelongsToMany(typeof(Role),
Table = "usr_role_link", ColumnKey = "user_id", ColumnRef
= "role_id",
Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Lazy =
true)]
public IList<Role> Roles { get; set; }
}
}
[/code]
My Role.cs is defined here :
[code]
namespace jTekPos.Data.Model
{
[Serializable]
[DataContract]
[ActiveRecord("user_role")]
public class Role : ActiveRecordBase<Role>
{
[DataMember]
[PrimaryKey("role_id")]
public int RoleId { get; set; }
[DataMember]
[Property("role_name")]
public String RoleName { get; set; }
[DataMember]
[Property("role_desc")]
public String RoleDescription { get; set; }
[DataMember]
[HasAndBelongsToMany(typeof(User),
Table = "user_role_link", ColumnKey = "role_id", ColumnRef
= "user_id",
Inverse = true, Cascade =
ManyRelationCascadeEnum.SaveUpdate, Lazy = true)]
public IList<User> Users { get; set; }
[DataMember]
[HasAndBelongsToMany(typeof(Permission),
Table = "role_perm_link", ColumnKey = "role_id", ColumnRef
= "perm_id",
Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Lazy =
true)]
public IList<Permission> Permissions { get; set; }
}
}
[/code]
The DAO that I expose (UserDAO.cs) :
[code]
namespace jTekPos.Data.AccessObject
{
[ServiceContract(Namespace="www.#####co.za/jTekPos/
DataAccessObject/User")]
[ServiceBehavior(IncludeExceptionDetailInFaults=true,
MaxItemsInObjectGraph=1000)]
public class UserDao : StandardDao<User>
{
[OperationContract]
[PreserveCircularReferences]
public virtual User FindUserById( int id )
{
return GetSingleResultFromCriteria
(MakeOneParamSimpleEqCriteria("Id", id));
}
[OperationContract]
[PreserveCircularReferences]
public virtual User FindUserByUsername(String username)
{
return GetSingleResultFromCriteria
(MakeOneParamSimpleEqCriteria("Username", username));
}
}
}
[/code]
The UserDao extends StandardDAO.cs thats this :
[code]
namespace jTekPos.Data.AccessObject
{
public abstract class StandardDao<T>
{
public readonly ISession _Session;
public T _BaseEntity;
public StandardDao()
{
ISessionFactory factory =
ObjectFactory.GetInstance<ISessionFactory>();
_Session = factory.OpenSession();
_BaseEntity = (T)
typeof(T).GetConstructor(new Type[]{}).Invoke(new
Object[]{});
}
public ICriteria MakeCriteria()
{
return _Session.CreateCriteria(typeof(T).Name);
}
public ICriteria MakeOneParamSimpleEqCriteria(String
PropertyName, Object Value)
{
ICriteria crit = MakeCriteria();
crit.Add(Restrictions.Eq(PropertyName, Value));
return crit;
}
public T GetSingleResultFromCriteria(ICriteria iCrit)
{
iCrit.SetMaxResults(1);
IList<T> lst = iCrit.List<T>();
if (lst == null || lst.Count == 0)
return default(T);
return lst[0];
}
}
}
[/code]
I followed an Microsoft article recommending me to create these
(supposed to help the dataContractSerializer preserver my
references) :
[b]OpBehaviourPreserveRefs.cs[/b]
[code]
public class OpBehaviourPreserveRefs :
DataContractSerializerOperationBehavior
{
public OpBehaviourPreserveRefs ( OperationDescription
operationDescription) : base(operationDescription) { }
public override XmlObjectSerializer CreateSerializer( Type
type, string name, string ns, IList<Type> knownTypes)
{
return CreateDataContractSerializer(type, name, ns,
knownTypes);
}
private static XmlObjectSerializer
CreateDataContractSerializer( Type type, string name, string ns,
IList<Type> knownTypes)
{
return CreateDataContractSerializer(type, name, ns,
knownTypes);
}
public override XmlObjectSerializer CreateSerializer( Type
type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type>
knownTypes)
{
return new DataContractSerializer(type, name, ns,
knownTypes, 0x7FFF, false, true, null);
}
}
[/code]
[b]The attribute : [/b]
[code]
public class PreserveCircularReferencesAttribute : Attribute,
IOperationBehavior
{
public void AddBindingParameters(OperationDescription
description, BindingParameterCollection parameters) { }
public void ApplyClientBehavior(OperationDescription
description, ClientOperation proxy) {
IOperationBehavior innerBehavior =
new OpBehaviourPreserveRefs(description);
innerBehavior.ApplyClientBehavior(description, proxy);
}
public void ApplyDispatchBehavior(OperationDescription
description, DispatchOperation dispatch)
{
IOperationBehavior innerBehavior =
new OpBehaviourPreserveRefs(description);
innerBehavior.ApplyDispatchBehavior(description,
dispatch);
}
public void Validate(OperationDescription description) { }
}
[/code]
And Then to host these I tried the standard selfHost option, and tried
the WcfIntegration package from Castle :
[b]IServiceHostCache.cs[/b]
[code]
public abstract class IServiceHostCache
{
public const String URI_TEMPLATE =
"http://${BindAddress}:${Port}/jtek/wcf/${ServiceType}/$
{ServiceName}";
public IList<Object> RunningServiceHosts =
new List<Object>();
public abstract void HostService(String ServiceName, String
ServiceType, Type ServiceContractImpl);
public Uri GenerateServiceUri(string ServiceName, string
ServiceType)
{
return new Uri(URI_TEMPLATE
.Replace("${BindAddress}", "localhost")
.Replace("${Port}", "8000")
.Replace("${ServiceType}", ServiceType)
.Replace("${ServiceName}", ServiceName));
}
public abstract void Destroy();
[/code]
[b]Standard WCF impl:[/b]
[code]
public class WcfBasedServiceHostCache : IServiceHostCache
{
public override void HostService(String ServiceName, String
ServiceType, Type ServiceContractImpl)
{
Uri uri = GenerateServiceUri( ServiceName, ServiceType );
ServiceHost host =
new ServiceHost( ServiceContractImpl , uri );
try
{
host.AddServiceEndpoint(
ServiceContractImpl,
new WSHttpBinding(),
ServiceName);
ServiceMetadataBehavior httpGetBehaviour =
new ServiceMetadataBehavior();
httpGetBehaviour.HttpGetEnabled = true;
host.Description.Behaviors.Add( httpGetBehaviour );
host.Open();
RunningServiceHosts.Add(host);
}
catch (CommunicationException ce)
{
host.Abort();
throw new Exception("Something Bad Happened", ce);
}
}
public override void Destroy()
{
foreach (ServiceHost host in RunningServiceHosts)
{
host.Close();
}
this.RunningServiceHosts.Clear();
}
}
[/code]
[b]The Windsor Impl[/b]
[code]
public class WindsorServiceHostCache : IServiceHostCache
{
public override void HostService(String ServiceName, String
ServiceType, Type ServiceContractImpl)
{
Uri uri = this.GenerateServiceUri(ServiceName,
ServiceType);
DefaultServiceHostFactory.RegisterContainer
(((IWindsorContainer) ObjectFactory.FetchDelegate()).Kernel);
DefaultServiceHost host =
new DefaultServiceHost(ServiceContractImpl, uri);
try
{
host.AddServiceEndpoint(
ServiceContractImpl,
new WSHttpBinding(),
ServiceName);
ServiceMetadataBehavior httpGetBehaviour =
new ServiceMetadataBehavior();
httpGetBehaviour.HttpGetEnabled = true;
host.Description.Behaviors.Add(httpGetBehaviour);
host.Open();
RunningServiceHosts.Add(host);
}
catch (CommunicationException ce)
{
host.Abort();
throw new Exception("Something Bad Happened", ce);
}
this.RunningServiceHosts.Add(host);
}
public override void Destroy()
{
foreach (DefaultServiceHost host in
this.RunningServiceHosts)
{
host.Close();
}
this.RunningServiceHosts.Clear();
}
}
[/code]
[b]My Application Configuration[/b]
[code]
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="castle"
type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler,
Castle.Windsor" />
</configSections>
<castle>
<facilities>
<!-- NHibernate Active Record Facility -->
<facility
id="arfacility"
type="Castle.Facilities.ActiveRecordIntegration.ActiveRecordFacility,
Castle.Facilities.ActiveRecordIntegration"
isDebug="true"
isWeb="false">
<assemblies>
<item>jTekPos.Data.Model</item>
</assemblies>
<config>
<add key="connection.driver_class"
value="NHibernate.Driver.MySqlDataDriver" />
<add key="dialect" value="NHibernate.Dialect.MySQLDialect" />
<add key="connection.provider"
value="NHibernate.Connection.DriverConnectionProvider" />
<add key="connection.connection_string"
value="Database=jtekposclientdb;Data Source=localhost;User
Id=root;Password=mrozio" />
<add key="proxyfactory.factory_class"
value="NHibernate.ByteCode.LinFu.ProxyFactoryFactory,
NHibernate.ByteCode.LinFu" />
<add key="hbm2ddl.keywords" value="none" />
</config>
</facility>
<!-- ActiveRecord Automatic Transaction Management -->
<facility
id="atm"
type="Castle.Facilities.AutomaticTransactionManagement.TransactionFacility,
Castle.Facilities.AutomaticTransactionManagement" />
</facilities>
</castle>
</configuration>
[/code]
And the remote client I use is basicly the selfgenerated code from
that svcutil.exe thing.
Sorry for asking you guys for help - But I have been struggling with
this whole project setup the whole of today and yesterday.
Please if I'm posting in the wrong place - just lemme know.
[/code]
--
You received this message because you are subscribed to the Google Groups
"Castle Project Users" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/castle-project-users?hl=en.