locked
Recap of our challenges RRS feed

  • Question

  • A list of typical challenges we're having with RIA Services (and/or such a platform):

    • Server side operations are asynchronous, cool! But there is no client side animation control to block the user interface while the operation is in progress. A typical example is the ServiceOperation which requires you to merge the result into the user interface. Sometimes you want to prevent the user from doing things in the meantime, since it might not make sense or overcomplicates the logic to handle this....
    • What happens when you have several pending asynchronous operations? Are these operations queued on the client by RIA? 
    • A physically tiered architecture challenges you the way you shape the service entities. There are two main design viewpoints:
      • you expose entities that map to your fine grained internal domain model. This probably fits best with Entity Framework/Linq to SQL.
      • you expose views on your internal domain model. This denormalizes entities and might make life easier on the client, databinding wise.
    • The term "entity" is overloaded. It can be an EF-entity, a POCO object exposed by the RIA domain service, etc. But it's definitly an entity on the client by looking at it's base class. Or is is a DataTransferObject? No it isn't, that's the entity ChangeSet being marshalled.
    • Real applications tend to use the Model-View-ViewModel design. The ViewModel helps creating easy databinding solutions. Maybe this pattern should be pushed some more in the examples?
    • There are at least two visions on how to value RIA Services:
      • it's intrusive and integrated part of your business logic/domain model. This is probably true if you start a new application and are able to use EF/L2S
      • you consider it to be another layer on top of your existing business logic (another facade). I treat it like this since we have an existing application that needs to be Silverlight enabled. We delegate most work to existing business logic residing in other DLL's. A challenge is the concept of shared logic through the automatic code generation mechanism. We might have some logic in our existing business logic DLL, which could be called from our domain service entity. But this logic isn't picked up as "shared class", so won't appear in the client. A typical example could be some calculation which could be performed both on the client as well as on the server. If you consider the domain service to be a facade, your business logic can't rely on this layer being available, since there can be other consumers of the business logic (direct cross DLL business logic calls for instance).
    • You can't manipulate the entity state client side. Why not? Why wouldn't I be able to insert an entity in a domain context and mark it as unmodified?
    • Not sure what the overhead/impact is of the ExcludeAttribute in combination with associated domain contexts on the client. Will each entity association be resolved on demand on the client?
    • typical preview issues, like:
      • custom and service operation are not working (anymore)
      • it's unclear what is a bug, what is misinterpretation of the framework and what will be solved (in the near future).
      • client side code generation seems to raise most questions/issues. It's unclear how this will change when the environment is operating in Visual Studio 2010, which seems to be the target environment. Some typical issues:
        • It seems like build performance is affected, since the code will be generated always (it least it feels that way). So if you have project dependencies it means dependent projects need to be rebuild as well.
        • Shared code via DLL's is hard due to the Silverlight/.Net framework target differences.
        • If you have several RIA-services libraries and common RIA services libraries with domain services referenced by the other RIA-services projects, you will get duplicate entities... Not sure if this is a bug or a conceptual issue.
        • If you partition your application, you expect DLL's to be lazy loaded. The Silverlight "minimize XAP-file size feature" to delay load and share DLL's via an assembly cache is great. The drawback is the fact that this mean no OutOfTheBrowser support. Why do they hae to be mutual exclusive? But this is more of a Silverlight v3 issue I guess....
    Sunday, August 9, 2009 4:50 AM

Answers

  • Each of EntityContainer, EntityList, and Entity implement IRevertibleChangeTracking, which has AcceptChanges/RejectChanges. Regarding "Merge" functionality, EntityContainer has the Load(IEnumerable<Entity>, MergeOption) method which allows you to load a set of entities for merge. If the entity being loaded is already attached, the values will be merged into the attached instance, otherwise the unattached entity will be attached.

     The overview document describes all of these APIs in more detail.

    Monday, August 17, 2009 1:19 PM

All replies

  • I am numbering only by the first level

    1. There are some example controls out there to track RIA Services activity and block users from making additional changes, however they all require the DDS to function correctly.
    2. They aren't queued, they run simultaneously.
    3. No comment
    4. The RIA Services objects are Entities, the EDM/POCO/L2S objects are Domain Objects and the EDM/POCO/L2S itself is the Domain. Generally speaking it is Entity <> DomainContext <> DomainService <> Domain
    5. Agreed. Shawn Wildermuth updated his MVVM example last week to use RIA Services. I need to create one myself but I haven't even had time to read this forum the last couple of days.
    6. I think the story of integrating with existing rules will get better as time goes by, but at least for now drinking the koolaid is much easier.
    7. Agree on this one, not being able to change the EntityState would open up a ton of interesting options. I do think this should be a new method which is marked not to shop up in intellisense.
    8. Not sure either
    9. I haven't noticed any build performance problems myself. I have been wondering if removing the ability to RIA Link application projects and the restricting the RIA Link to a one to one relationship (one client side class library to one server side class library) would clean up the conceptual problems.
    Monday, August 10, 2009 5:07 PM
  • Theo,

     Thanks for your feedback. One quick comment:

    Theo > You can't manipulate the entity state client side. Why not? Why wouldn't I be able to insert an entity in a domain context and mark it as unmodified?
     
    Support for unmodified entity already exists in the form of Attach(). After modification, it will result in an update rather than an insert. Add() is for inserting new objects. This is the pattern prevalent in mid-tier DALs. Detach() is the counterpart if you don't want to trigger delete on server.
     
    From the "Go to definition" on EntityList
     
            // Summary:
            //     Attaches the specified System.Windows.Ria.Data.Entity to this System.Windows.Ria.Data.EntityList
            //     in an unmodified state, also recursively attaching all unattached entities
            //     reachable via associations.
            //
            // Parameters:
            //   entity:
            //     The entity to attach
            //
            // Remarks:
            //     The entity needs to be of type TEntity, and cannot be a subclass.
            public void Attach(TEntity entity);
    Friday, August 14, 2009 4:42 PM
  • 1)

    The (great) Activity control does not need a DDS to work. Any control that exposes the property IsBusy will do, if you are

    using the AutoBind=true.

    If you not using the AutoBind, you can bind the IsActive property of the control to your VM and have all the control you want.

     

    Friday, August 14, 2009 5:27 PM
  • 1)

    The (great) Activity control does not need a DDS to work. Any control that exposes the property IsBusy will do, if you are

    using the AutoBind=true.

    If you not using the AutoBind, you can bind the IsActive property of the control to your VM and have all the control you want.

    Good point, I was vastly overstatting the reliance on the DDS. Still, while I love the look of that control, I don't like the idea of creating a control in my XAML just to expose an IsActive property and binding to the VM simply doesn't work for the way my application is structured. What I am planning to create is a version of that Activity control that receives OperationBase objects through Event Aggregator.

    Friday, August 14, 2009 5:42 PM
  • Colin,

    I didn't create a control, but I created a simple class, that listens to events (I'm using CAL) and can be

    added as a resource.

    I than bind the IsActive property of the Activity control to this resource. Works great.

    I can have multiple activity controls if I want and I can have multiple resources too.

    The event to listen to is a property of the control manager. 

    ---

    Something like below:


    <UserControl.Resources>
            <mynamespace:ActivityControlManager
                x:Key="activityControlManager"
                EventToListenTo="....."/>
    </UserControl.Resources>

    <Activity ...
    IsActive="{Binding Path=IsBusy, Mode=OneWay, Source={StaticResource activityControlManager}}"
    ActiveContent="{Binding Path=ActivityContent, Mode=OneWay, Source={StaticResource activityControlManager}}">
    ...
    ...
    </Activity>

     

    Friday, August 14, 2009 5:58 PM
  • Nice, I had considered a similar strategy. The reason I am building a new control is I want something that can expand to look like the activity screen in SQL Server. For example, the screen that shows up when you are doing an import/export. Then if one of the operations fails it will get the red X and have an error message viewer.

    Friday, August 14, 2009 6:14 PM
  • Support for unmodified entity already exists in the form of Attach().
     
    OK, but I was thinking more in the area of "Entity.AcceptChanges()" for an already attached entity or "DomainContext.Entities.Merge(Entity entity,...)". The System.Data.DataSet started with a fully closed state API, but later on support was added to mark a DataRow modified for instance. So there is probably a need for more control in particular scenarios.
    Saturday, August 15, 2009 3:41 AM
  • Each of EntityContainer, EntityList, and Entity implement IRevertibleChangeTracking, which has AcceptChanges/RejectChanges. Regarding "Merge" functionality, EntityContainer has the Load(IEnumerable<Entity>, MergeOption) method which allows you to load a set of entities for merge. If the entity being loaded is already attached, the values will be merged into the attached instance, otherwise the unattached entity will be attached.

     The overview document describes all of these APIs in more detail.

    Monday, August 17, 2009 1:19 PM
  • Wow, if everything is already there.... how could I have overlooked the functionality? I will give it a try to see how it works, thanks again!

    Monday, August 17, 2009 1:22 PM
  • Each of EntityContainer, EntityList, and Entity implement IRevertibleChangeTracking, which has AcceptChanges/RejectChanges. Regarding "Merge" functionality, EntityContainer has the Load(IEnumerable<Entity>, MergeOption) method which allows you to load a set of entities for merge. If the entity being loaded is already attached, the values will be merged into the attached instance, otherwise the unattached entity will be attached.

     The overview document describes all of these APIs in more detail.

    If the help documentation is correct, that is LoadEntities(IEnumerable<Entity>, MergeOption) on the EntityContainer and, as far as I can tell, it was never mentioned in the overview document. I definitly missed that LoadEntities function, that is going to be very useful for caching readonly entities. Now, if we had a MergeOption that added unmerged entities as New and merged entities as modified and another MergeOption that just merges everything as modified then we could get some offline capability into RIA Services.

    Monday, August 17, 2009 1:55 PM
  • I guess I forgot to mention the Load method in the change tracking documentation I wrote :) Regarding offline, all the building blocks you need should already be there. There is an "OfflineStorage" sample as part of the authentication samples here http://code.msdn.microsoft.com/RiaServices/Release/ProjectReleases.aspx?ReleaseId=2661 that demonstrates use of these APIs. That sample saves off the current state of a DomainContext (including all entity modifications) into isolated storage, and rehydrates it later. APIs needed for offline and shown in the sample include: Entity.GetOriginal, EntityList.Add, EntityList.Attach.

    Monday, August 17, 2009 2:36 PM
  • To me, the core of that code is that you reimplemented the Entity's private ApplyState method to use a passed in Entity. The primary differences are that ApplyState takes in an IDictionary instead of an Entity and ApplyState only copies properties that are DataMembers while the OfflineStorage example, if I am reading it correctly, assumes that all properties are DataMembers. If somebody at Microsoft would just post up the actual code for ApplyState, ExtractState, and GetDataMembers and said we could use it then that would help a lot. Hint Hint.

    Monday, August 17, 2009 3:25 PM
  • For determination of which members are data members from our perspective, they're simply any public instance members that are marked with DataMemberAttribute and are not read-only. You're right that our internal implementation is doing its own checks in GetDataMembers, but I'm actually going to change that to be the simple test above. With that, ApplyState/Extract state just copy values.

    Monday, August 17, 2009 8:00 PM
  • Another question mathew, is there a reason you were using p.GetSetMethod != null instead of p.CanWrite?

    Tuesday, August 18, 2009 10:06 AM
  • I recently discovered that CanWrite will return true even if the setter is private. Then when you call p.SetValue, you get a MethodAccessException. However, p.GetSetMethod will return null if the method is not public which avoids the problem altogether.

    Kyle

    Tuesday, August 18, 2009 10:50 AM
  • I recently discovered that CanWrite will return true even if the setter is private. Then when you call p.SetValue, you get a MethodAccessException. However, p.GetSetMethod will return null if the method is not public which avoids the problem altogether.

    Kyle

    I found a Connect feedback that seems to be about that issue. Thanks for the reply.

    Tuesday, August 18, 2009 10:58 AM