Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to expose calculated data of an entity through WCF

Tags:

c#

wcf

poco

We’re developing an N-tier architecture application using WCF between client (presentation) and server (data/business layer). To be honest I can’t find any real examples/info of how to expose efficiently calculated data through WCF.

For describing my problem say we have ATM machines which have lots of transactions. So we have an 1-N relation between ATM Class and Transaction class. ATM Class has properties like Location, ModelNo, Description, InstallDate and the Transaction records have info like Amount, DateTime, CustomerInfo, TicketPaperLength, ElectricityUsed

Exposing these classes through WCF is not the issue. Problem is that we have lots of calculated fields for ATM that are based on the underlying Transaction table. For example, the client application uses reports based on the calculated data of ATM. Examples of calculated data of ATM could be: AverageTicketPaperLength, AverageAmount, DeviationAmount, AverageElectricity, etc, etc. There are lots and lots of these calculated data. The calculations should take place on the server and not on the client-side. If these report definitions were all fixed it wouldn’t be that big a problem: we could create separate services/Poco’s, for the reports. Put the calculations in a business layer and fill the Poco as needed. But the client application must have the ability to make reports filtered on whatever set of calculated properties of ATM and return as data another set of (calculated) properties.

I could create a Poco with about 500 calculated properties where there for each single report only may be 10 properties would be used. But of course we don’t want all 500 calculations executed every time for each and every entity.

So in general I’m wondering how one would expose calculated data of an entity through e.g. WCF. Almost all examples I see explaining Entity Framework, Poco and WCF only deal with the persistent fields of the entity and that is pretty straight-forward.

like image 618
Erik Avatar asked Dec 19 '12 11:12

Erik


1 Answers

Do not expose entities through WCF, create some DTOs.

For example:

In wcf layer -

DtoInfoForReport1 GetInfoForReport1(long atmId) { ... call BL here... } 
DtoInfoForReport2 GetInfoForReport2(long atmId) { ... call BL here... }

In data layer -

AtmEntity
{
  long Id {get;set;}
  ... some properties ...
  HashSet<Transaction> AtmTransactions {get;set;}
}

Transfer objects -

DtoInfoForReport1
{
  long AtmId {get;set;}
  XXX SomeCalculatedValue {get;set;}
}

In BL -

DtoInfoForReport1 CreateInfoForReport1(long atmId)
{
  var atm = YYY.GetEntity<AtmEntity>(atmId);
  return new DtoInfoForReport1
  {
    AtmId = atmId,
    SomeCalculatedValue = DoSomeCalculationOverMyAtmWithItsTransactions(atm),
  };
}

Hope I got your question right. Otherwise comment.

Edit based on comment: Than I would suggest DTOs like this:

[DataContract]
public DtoRequestedCalculations
{
  [DataMember]
  public long AtmId {get;set;}

  [DataMember]
  public List<DtoRequestedCalculationEntry> Calculations {get;set;}
}

[DataContract]
public DtoRequestedCalculationEntry
{
  [DataMember]
  public string / long / Guid / XXX ParameterIdentifier {get;set;}

  [DataMember]
  public double/ DtoParameterCalculatedValueBase {get;set;}
}

Now if your calculated value is always double it's basically done. If your values may be or different types you will need some base class - DtoParameterCalculatedValueBase, which is sth like this:

[DataContract]
[KnownType(typeof(DtoParameterDoubleCalculatedValue))]
[KnownType(typeof(DtoParameterXXXCalculatedValue))]
public DtoParameterCalculatedValueBase 
{
  ...whatever common part there may be or nth...
}

public DtoParameterDoubleCalculatedValue : DtoParameterCalculatedValueBase 
{
  [DataMember]
  public double Value {get;set;}
}

public DtoParameterXXXCalculatedValue : DtoParameterCalculatedValueBase 
{
  [DataMember]
  public XXX Value {get;set;}
}

Note the KnownType attribute - it tells WCF what types may come in place of base class. You will have to provide this attribute for each inherited type (or use DataContractResolver, which is already another story).

Than in WCF:

DtoRequestedCalculations GetCalculatedValuesForAtm(long atmId, List<long / string/ Guid / XXX> valueIdentifiers);
like image 192
Maxim Zabolotskikh Avatar answered Dec 16 '22 14:12

Maxim Zabolotskikh