locked
WCF Data Services and Business Logic? RRS feed

  • Question

  • My plain html (so NO webforms/code behind) page talks to WCF Data Services by using Microsoft Ajax Client Library. On my server side I have EF 4 with POCO's and SQL Server datastore. I should add my business logic to these POCO's. But, I don't see how I can use this business logic when using WCF Data Services?
    I only see, in my scenario, the possibility of adding my business logic to wcf data services Query/Change Interceptors; is this correct or how could I use the business logic from my POCO's using WCF Data Services?

    Thanks.

    Friday, September 10, 2010 3:57 PM

Answers

  • You can code your own datasource object (must implement IDataServiceUpdateProvider if you want to be able to perform create/update/delete on the datasource)

    Here is a sample code... it is not completed yet but i think its a good start ...

    ForumDataContext is an EF datasource.

    Items entity set of the EF datasource contains different type of items... maybe yours is not as complex as this one but i dont have time to rewrite a simpler example... DataAccess namespace contain my EF real entities that i dont expose... this give me much more flexibility upon adding any businness logic that i want.... this way my EF datasource is not coupled to my WCF data service...

    Query interceptor of course can help you add logic but are very limited

    public class ForumData : IDataServiceUpdateProvider
     {
    
     User _currentUser;
     ForumDataContext _dataContext;
     public ForumData()
     {
     _dataContext = new ForumDataContext();
    
     _currentUser = _dataContext.Items.OfType<User>().Where(usr => usr.ExternalId == HttpContext.Current.User.Identity.Name).FirstOrDefault();
     if (_currentUser == null)
     throw new UnauthorizedAccessException();
     }
    
     internal ForumDataContext DataContext {
     get { return this._dataContext; }
     }
     public PublicEntities.User CurrentUser {
     get { return new PublicEntities.User { Data = this._currentUser }; }
     }
    
     public IQueryable<PublicEntities.Site> Sites
     {
     get
     {
    
     var items =( from itm in _dataContext.Items.OfType<Site>() select itm).ToList().AsQueryable();
     return from itm in items select new PublicEntities.Site { Data = itm }; ;
     }
     }
    
    
     public IQueryable<PublicEntities.User> Users
     {
     get
     {
     return from itm in _dataContext.Items.OfType<User>().ToList().AsQueryable()
     select new PublicEntities.User { Data = itm };
     }
     }
    
    
     void IDataServiceUpdateProvider.SetConcurrencyValues(object resourceCookie, bool? checkForEquality, IEnumerable<KeyValuePair<string, object>> concurrencyValues)
     {
     throw new NotImplementedException();
     }
    
     void System.Data.Services.IUpdatable.AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded)
     {
     throw new NotImplementedException();
     }
    
     void System.Data.Services.IUpdatable.ClearChanges()
     {
     throw new NotImplementedException();
     }
    
     object System.Data.Services.IUpdatable.CreateResource(string containerName, string fullTypeName)
     {
     PublicEntities.Item item;
    
     System.Type type = this.GetType().Assembly.GetType(fullTypeName.Replace("_", "+"));
    
    
     if (type.Equals(typeof(PublicEntities.Site)))
     {
     item = new PublicEntities.Site { Data = new Site() };
    
    
     }
     else if (type.Equals(typeof(PublicEntities.User)))
     {
     item = new PublicEntities.User();
     }
     else
     {
     throw new NotImplementedException();
     }
    
     if (item != null)
     {
     item.Data.Id = Guid.NewGuid();
     DateTime dateCreated = DateTime.Now;
     item.Data.CreatedBy = _currentUser;
     item.Data.ModifiedBy = _currentUser;
     item.Data.CreatedDate = dateCreated;
     item.Data.ModifiedDate = dateCreated;
     }
     _dataContext.AddObject("Items", item.Data);
    
     return item;
     }
    
     void System.Data.Services.IUpdatable.DeleteResource(object targetResource)
     {
     Item item = default(Item);
     if (targetResource is PublicEntities.Site)
     {
     item = _dataContext.Items.OfType<Site>().Where(itm => itm.Id.Equals(((PublicEntities.Site)targetResource).Id)).Single();
     }
     else
     {
     throw new NotImplementedException();
     }
     _dataContext.Items.DeleteObject(item);
     }
    
     object System.Data.Services.IUpdatable.GetResource(IQueryable query, string fullTypeName)
     {
     return query.Cast<PublicEntities.Item>().FirstOrDefault();
     }
    
     object System.Data.Services.IUpdatable.GetValue(object targetResource, string propertyName)
     {
     throw new NotImplementedException();
     }
    
     void System.Data.Services.IUpdatable.RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved)
     {
     throw new NotImplementedException();
     }
    
     object System.Data.Services.IUpdatable.ResetResource(object resource)
     {
     throw new NotImplementedException();
     }
    
     object System.Data.Services.IUpdatable.ResolveResource(object resource)
     {
    
     object obj = null;
     if (resource is PublicEntities.Site)
     {
     obj = (from itm in _dataContext.Items.OfType<Site>() where itm.Id.Equals(((PublicEntities.Site)resource).Id) select new PublicEntities.Site { Data = itm }).Single();
     }
     else
     {
     throw new NotImplementedException();
     }
     return obj;
     }
    
     void System.Data.Services.IUpdatable.SaveChanges()
     {
     _dataContext.SaveChanges(System.Data.Objects.SaveOptions.AcceptAllChangesAfterSave);
     }
    
     void System.Data.Services.IUpdatable.SetReference(object targetResource, string propertyName, object propertyValue)
     {
     throw new NotImplementedException();
    
     }
    
    
     void System.Data.Services.IUpdatable.SetValue(object targetResource, string propertyName, object propertyValue)
     {
     TypeDescriptor.GetProperties(targetResource)[propertyName].SetValue(targetResource, propertyValue);
     }
     }
    
    
    namespace PublicEntities 
    { [DataServiceKey("Id")]
     public class Item
     {
     internal DataAccess.Item Data { get; set; }
    
     internal Item() { }
    
     public Guid Id
     {
     get { return Data.Id; }
     }
     public string DisplayName
     {
     get { return Data.DisplayName; }
     set { Data.DisplayName = value; }
     }
     }
    
     public class User : Item
     {
     public User()
     {
     Data = new DataAccess.User();
     }
     internal new DataAccess.User Data
     {
     get { return (DataAccess.User)base.Data; }
     set { base.Data = value; }
     }
    
    
     }
    
     public class Site : Item
     {
     public Site()
     {
     base.Data = new DataAccess.Site();
     }
     internal new DataAccess.Site Data
     {
     get { return (DataAccess.Site)base.Data; }
     set { base.Data = value; }
     }
    
     public string Name
     {
     get { return Data.Name; }
     set { Data.Name = value; }
     }
     public User CreatedBy
     {
     get { return new User { Data = Data.CreatedBy }; }
     }
     public User ModifiedBy
     {
     get { return new User { Data = Data.ModifiedBy }; }
     }
    
     }
    }
    

     

    Sunday, September 12, 2010 4:45 PM

All replies

  • You can code your own datasource object (must implement IDataServiceUpdateProvider if you want to be able to perform create/update/delete on the datasource)

    Here is a sample code... it is not completed yet but i think its a good start ...

    ForumDataContext is an EF datasource.

    Items entity set of the EF datasource contains different type of items... maybe yours is not as complex as this one but i dont have time to rewrite a simpler example... DataAccess namespace contain my EF real entities that i dont expose... this give me much more flexibility upon adding any businness logic that i want.... this way my EF datasource is not coupled to my WCF data service...

    Query interceptor of course can help you add logic but are very limited

    public class ForumData : IDataServiceUpdateProvider
     {
    
     User _currentUser;
     ForumDataContext _dataContext;
     public ForumData()
     {
     _dataContext = new ForumDataContext();
    
     _currentUser = _dataContext.Items.OfType<User>().Where(usr => usr.ExternalId == HttpContext.Current.User.Identity.Name).FirstOrDefault();
     if (_currentUser == null)
     throw new UnauthorizedAccessException();
     }
    
     internal ForumDataContext DataContext {
     get { return this._dataContext; }
     }
     public PublicEntities.User CurrentUser {
     get { return new PublicEntities.User { Data = this._currentUser }; }
     }
    
     public IQueryable<PublicEntities.Site> Sites
     {
     get
     {
    
     var items =( from itm in _dataContext.Items.OfType<Site>() select itm).ToList().AsQueryable();
     return from itm in items select new PublicEntities.Site { Data = itm }; ;
     }
     }
    
    
     public IQueryable<PublicEntities.User> Users
     {
     get
     {
     return from itm in _dataContext.Items.OfType<User>().ToList().AsQueryable()
     select new PublicEntities.User { Data = itm };
     }
     }
    
    
     void IDataServiceUpdateProvider.SetConcurrencyValues(object resourceCookie, bool? checkForEquality, IEnumerable<KeyValuePair<string, object>> concurrencyValues)
     {
     throw new NotImplementedException();
     }
    
     void System.Data.Services.IUpdatable.AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded)
     {
     throw new NotImplementedException();
     }
    
     void System.Data.Services.IUpdatable.ClearChanges()
     {
     throw new NotImplementedException();
     }
    
     object System.Data.Services.IUpdatable.CreateResource(string containerName, string fullTypeName)
     {
     PublicEntities.Item item;
    
     System.Type type = this.GetType().Assembly.GetType(fullTypeName.Replace("_", "+"));
    
    
     if (type.Equals(typeof(PublicEntities.Site)))
     {
     item = new PublicEntities.Site { Data = new Site() };
    
    
     }
     else if (type.Equals(typeof(PublicEntities.User)))
     {
     item = new PublicEntities.User();
     }
     else
     {
     throw new NotImplementedException();
     }
    
     if (item != null)
     {
     item.Data.Id = Guid.NewGuid();
     DateTime dateCreated = DateTime.Now;
     item.Data.CreatedBy = _currentUser;
     item.Data.ModifiedBy = _currentUser;
     item.Data.CreatedDate = dateCreated;
     item.Data.ModifiedDate = dateCreated;
     }
     _dataContext.AddObject("Items", item.Data);
    
     return item;
     }
    
     void System.Data.Services.IUpdatable.DeleteResource(object targetResource)
     {
     Item item = default(Item);
     if (targetResource is PublicEntities.Site)
     {
     item = _dataContext.Items.OfType<Site>().Where(itm => itm.Id.Equals(((PublicEntities.Site)targetResource).Id)).Single();
     }
     else
     {
     throw new NotImplementedException();
     }
     _dataContext.Items.DeleteObject(item);
     }
    
     object System.Data.Services.IUpdatable.GetResource(IQueryable query, string fullTypeName)
     {
     return query.Cast<PublicEntities.Item>().FirstOrDefault();
     }
    
     object System.Data.Services.IUpdatable.GetValue(object targetResource, string propertyName)
     {
     throw new NotImplementedException();
     }
    
     void System.Data.Services.IUpdatable.RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved)
     {
     throw new NotImplementedException();
     }
    
     object System.Data.Services.IUpdatable.ResetResource(object resource)
     {
     throw new NotImplementedException();
     }
    
     object System.Data.Services.IUpdatable.ResolveResource(object resource)
     {
    
     object obj = null;
     if (resource is PublicEntities.Site)
     {
     obj = (from itm in _dataContext.Items.OfType<Site>() where itm.Id.Equals(((PublicEntities.Site)resource).Id) select new PublicEntities.Site { Data = itm }).Single();
     }
     else
     {
     throw new NotImplementedException();
     }
     return obj;
     }
    
     void System.Data.Services.IUpdatable.SaveChanges()
     {
     _dataContext.SaveChanges(System.Data.Objects.SaveOptions.AcceptAllChangesAfterSave);
     }
    
     void System.Data.Services.IUpdatable.SetReference(object targetResource, string propertyName, object propertyValue)
     {
     throw new NotImplementedException();
    
     }
    
    
     void System.Data.Services.IUpdatable.SetValue(object targetResource, string propertyName, object propertyValue)
     {
     TypeDescriptor.GetProperties(targetResource)[propertyName].SetValue(targetResource, propertyValue);
     }
     }
    
    
    namespace PublicEntities 
    { [DataServiceKey("Id")]
     public class Item
     {
     internal DataAccess.Item Data { get; set; }
    
     internal Item() { }
    
     public Guid Id
     {
     get { return Data.Id; }
     }
     public string DisplayName
     {
     get { return Data.DisplayName; }
     set { Data.DisplayName = value; }
     }
     }
    
     public class User : Item
     {
     public User()
     {
     Data = new DataAccess.User();
     }
     internal new DataAccess.User Data
     {
     get { return (DataAccess.User)base.Data; }
     set { base.Data = value; }
     }
    
    
     }
    
     public class Site : Item
     {
     public Site()
     {
     base.Data = new DataAccess.Site();
     }
     internal new DataAccess.Site Data
     {
     get { return (DataAccess.Site)base.Data; }
     set { base.Data = value; }
     }
    
     public string Name
     {
     get { return Data.Name; }
     set { Data.Name = value; }
     }
     public User CreatedBy
     {
     get { return new User { Data = Data.CreatedBy }; }
     }
     public User ModifiedBy
     {
     get { return new User { Data = Data.ModifiedBy }; }
     }
    
     }
    }
    

     

    Sunday, September 12, 2010 4:45 PM
  • Hi,

     

    I am writing to check the status of the issue on your side.  Would you mind letting us know the result of the suggestions? 

     

    If you need further assistance, please feel free to let me know.   I will be more than happy to be of assistance.

     

    Have a nice day!

     

     

    Best Regards,
    Lingzhi Sun

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Tuesday, September 14, 2010 8:56 AM
    Moderator