CSLA 4/ Silverlight 4
I have a "IsExists" rule to check for duplicate object with the same name. This rule was initially set up as an Async rule that triggers a command object. I am trying to modify it , so it runs async ONLY if it is executed on client/silverlight. I am not having much success. Can someone fill in the blanks for me ?
Here is the code -
public class DuplicateRule : Csla.Rules.BusinessRule
{
public Csla.Core.IPropertyInfo IdProperty { get; set; }
public DuplicateRule (Csla.Core.IPropertyInfo primaryProperty, Csla.Core.IPropertyInfo idProperty)
: base(primaryProperty)
{
IsAsync = (Csla.ApplicationContext.LogicalExecutionLocation != ApplicationContext.LogicalExecutionLocations.Server);
IdProperty = idProperty;
InputProperties = new List<Csla.Core.IPropertyInfo>();
InputProperties.Add(primaryProperty);
InputProperties.Add(idProperty);
}
protected override void Execute (Csla.Rules.RuleContext context)
{
var name = (string)context.InputPropertyValues[PrimaryProperty];
var Id = (Guid)context.InputPropertyValues[IdProperty];
if (IsAsync)
{
DomainExists command = new DomainExists(name, Id);
DataPortal<DomainExists> dpCmd = new DataPortal<DomainExists>();
dpCmd.ExecuteCompleted += (o, e) =>
{
if (e.Error != null)
context.AddErrorResult(e.Error.Message);
else if (e.Object.IsExists)
context.AddErrorResult("This domain name already exists.");
context.Complete();
};
dpCmd.BeginExecute(command);
}
else
{
…What goes here….
}
}
}
Thanks
Ranjini
Since Silverlight has async methods only you probably need to add a compiler directive so the sync code only runs in .NET.
You should test for ExecutionLocation (and not LogicalExecutionLocation) and the rule should look like this:
public class DuplicateRule : Csla.Rules.BusinessRule
{
public Csla.Core.IPropertyInfo IdProperty { get; set; }
public DuplicateRule (Csla.Core.IPropertyInfo primaryProperty, Csla.Core.IPropertyInfo idProperty)
: base(primaryProperty)
{
IsAsync = (Csla.ApplicationContext.ExecutionLocation != ApplicationContext.ExecutionLocations.Server);
IdProperty = idProperty;
InputProperties = new List<Csla.Core.IPropertyInfo>();
InputProperties.Add(primaryProperty);
InputProperties.Add(idProperty);
}
protected override void Execute (Csla.Rules.RuleContext context)
{
var name = (string)context.InputPropertyValues[PrimaryProperty];
var Id = (Guid)context.InputPropertyValues[IdProperty];
if (IsAsync)
{
DomainExists command = new DomainExists(name, Id);
DataPortal<DomainExists> dpCmd = new DataPortal<DomainExists>();
dpCmd.ExecuteCompleted += (o, e) =>
{
if (e.Error != null)
context.AddErrorResult(e.Error.Message);
else if (e.Object.IsExists)
context.AddErrorResult("This domain name already exists.");
context.Complete();
};
dpCmd.BeginExecute(command);
}
else
{
// use sync dataportal
#if !SILVERLIGHT
DomainExists command = new DomainExists(name, Id);
DataPortal<DomainExists> dpCmd = new DataPortal<DomainExists>();
dpCmd.Execute(command);
if (command.IsExists)
context.AddErrorResult("This domain name already exists.");
#endif
}
}
}
Thanks for your response..
I did try that but it gives me this exception
'Csla.DataPortal<DomainExists>' does not contain a definition for 'Execute' and no extension method 'Execute' accepting a first argument of type 'Csla.DataPortal<DomainExists>' could be found (are you missing a using directive or an assembly reference?)
DomainExists is a CommandBase object with a dataportal_execute implemented so..
protected override void DataPortal_Execute() {
using (var dalFactory = DAL.DalFactory.GetManager())
{
var dal = dalFactory.GetProvider<DAL.IDomainDal>();
using (var dr = new SafeDataReader(dal.Fetch((new DomainCriteria() { Name = Name}).StateBag)))
{
while (dr.Read())
{
if (dr.GetGuid("Id") != Id)
{
IsExists = true;
break;
}
}
}
}
}
Try this:
#if !SILVERLIGHT
DomainExists command = new DomainExists(name, Id);
command = DataPortal.Execute<DomainExists>(command);
if (command.IsExists)
context.AddErrorResult("This domain name already exists.");
#endif
Thanks Jonny.. That did compile. However, can you explain to me
1) The usecases for LogicalExecutionLocation vs ExecutionLocation
In my case , when I change it to ExecutionLocation, since it is returned as "Client" , it takes the async path .. What I am trying to do here is write a test method to exercise this rule on the server side and I dont want any async calls made.
2) Why DataPortal.Execute gives me a compile error?
Please help!
1. ExecutionLocation returns Client or Server depending on whether the code is actually executing on the client or server. If you're using the local data portal, this will ALWAYS return Client since there is no server tier. Logical returns Client or Server based on whether you're logically on the client or server. For for local data portal, if you're actually executing code "in the data portal" it will return server. Otherwise it will return client.
2. DataPortal.Execute static method is only available in .Net. In Silverlight, only the DataPortal instance member exist. Remember, code in Silverlight is a different runtime based on .Net 2. The normal .Net runtime is what most people are used to.
Thanks Andy.. I get (2), but I am still a little unclear on (1) and that may just be because I am not a CSLA pro... My solution is primarily a silverlight application, with a silverlight project, a business.client and a business.server set up. I am now in the process of testing JUST business.server and I started this conversation thread when I realised i cannot do this test unless i redid all my "IsExists" rules to handle client and server differently (async on client and sync on server).
When debugging the test project, I am noticing that when I try to run this rule(by changign the value of the primary property), it shows my executionlocation as "Client" but my logicalexecutionlocation as "Server". I am having a hard time wrapping my head around why this might be.
Thanks again for taking the time...
If you use LogicalExecutionLocation your rule will be async or sync depending on whether the first instance is created in a DataPortal call or directly on the client. When using Local DataPortal your code is running in the same instance and should not try to switch between client/server.
ExecutionLocation is Server if the DataPortal has IsRemoteDataPortal == true.
LogicalExecutionLocation is Server when you are in a DataPortal call
So in your case - ExecutionLocation is Client because you are running in the client instance and logical execution location is Server because you code is executing in the "serverside" of the DataPortal.
In which case then I should change my rule constructor to say
public DuplicateRule (Csla.Core.IPropertyInfo primaryProperty, Csla.Core.IPropertyInfo idProperty) : base(primaryProperty) { IsAsync = (Csla.ApplicationContext.ExecutionLocation == ApplicationContext.ExecutionLocations.Silverlight); IdProperty = idProperty; InputProperties = new List<Csla.Core.IPropertyInfo>(); InputProperties.Add(primaryProperty); InputProperties.Add(idProperty); } Would that be correct?
Thanks much for taking the time to answer my questions
Ranjini
For your app it would work fine, however for a more general solution I'd prefer:
IsAsync = (Csla.ApplicationContext.ExecutionLocation != ApplicationContext.ExecutionLocations.Server);
Copyright (c) Marimer LLC