Problem sharing domain model between WCF and Silverlight Project - c#

I am writing a Large Scale Silverlight Application.
I am currently writing the data retrieval elements.
I have now encoutered and issue.
I have a common Project that hold objects, this project is referenced by both the UI and the WCF service.
The UI requires INotifyPropertyChanged for binding purposes.
Now the WCF must use the same objects, but I am getting a compiler error saying
"The type
'System.ComponentModel.INotifyPropertyChanged'
is defined in an assembly that is not
referenced."
EDIT: The error is in the WCF service.
I want one object class, how do I solve this problem?
diagram http://www.pcbuyersguide.co.za/picture.php?albumid=19&pictureid=1708
Thanks
-Oliver

If you plan to use the same source code for your Entities (domain) for both a clr and silverlight project you will need to use 2 projects because the Silverlight assemblies are not the same as CLR assemblies.
Add a Silverlight Class Library project to your solution, the name is not important but I usually just use XXXX_SL.
Now, you will 'Add Existing Item' all of the source files from the clr project, but notice the dropdown on the open or select button? click that and 'add as link' or whatever it says there.
You are now using the same source for both projects and your solution will compile.
There may be some minor tweaks along the way but that will set you on the right path..
Here is some reference material

did you add a reference in the compiling project to System.ComponentModel

I found a method here that allows one to create the CLR classes on the service side and then one can use the generated objects from the Service Reference as the classes are generated with the INotifyPropertyChanged and ObservableCollection.
This solves the immediate problem of the client/server boundary but does fit into my solution because in order to use the generated objects you need the service reference. But I have a ProxyClass that does the talking to WCF so there I cannot see a way of passing these object types back to the ViewModel.
I see some people have written mapper classes, but this is far from ideal as I would have to write 3 classes for each POCO object (client class, server DTO class, mapper).
Any more suggestions?

Related

How to re-use a user control in two Silverlight client applications?

I'm kind of new to Silverlight and I have a solution which has one web project (webApp) that provides remote services and two client applications (client-1 and client-2) that uses these services.
I have created a complex user control in client-1 that view/edit an object retrieved from webApp and I want to re-use this control in client-2.
The problem is, when you reference the service from the client apps, the types are "locally-typed". For example, MyClass defined in the webApp becomes client-1.MyClass in client-1 app. Using exactly the same object (reference) in client-2 app, it is now of type client-2.MyClass
If I create a library to host my control, I will have to add a reference to the web services and I will have a third type, lib.MyClass. We all know that client-1.MyClass, client-2.MyClass and lib.MyClass are all exactly the same class that was generated from web.MyClass but I can't find a way around this problem.
I'm currently looking at sharing the source code of the user control in each client application and having pre-processor defines in each project so I can do this in my user control code file:
#if CLIENT-1
using Client-1.WebAppServiceReference
#end if
#if CLIENT-2
using Client-2.WebAppServiceReference
#end if
Then the method that uses the type MyClass are using the correct "local-type" in each client app. But I'm having problem since there is no pre-processor functionality in the xaml and there is a reference to the application's namespace there that I need to be conditional.
There's got a be an easier way of re-using controls accross silverlight projects, no?? There is no way I'm going to have two copies of the source files for this control, on in each project!!
Thanks!
There are a couple of options that allow you to use shared entity classes across Silverlight projects/WCF service proxies.
Use an RIA class library
Use a portable class library
If you create your DataContract classes with either of the above, and then reference the library from both your WCF and Silverlight client projects, then the auto-generated code will use a reference to those shared classes (rather than the locally auto-generated classes). This should allow you to re-use your Silverlight UserControls between projects.
The difference between the two approaches is this. If you use the first approach (RIA project), then when you create files named "SomeEntityClass.shared.cs", the ".shared" tells Visual Studio to place a copy of the file in a mirror Silverlight project. The second approach (PCL) is a newer approach -- it allows you to create class libraries that are capable of targeting multiple platforms (.Net, Silverlight, Windows Phone, ...), with a reduced set of core .NET libraries.
I suggest you to dissociate the XAML and graphical stuff from any of Business logics and the like. MVVM is a very good pattern to follow.
After that, you can reference your UserControl from second project with the very useful functionality of Visual Studio "Add as Link"
Here how you can do it :
For the underlying business, you can make it available for both project, and linking these 2 with it.
Hope it helps

Using multiple RIA silverlight links with shared server side entities

For a project I'm using Silverlight 4.0 with RIA and EntityFramework 4.0. I have three web projects:
Common.Web: contains general types
Workflow.Web: contains domainservices for workflows
Monitor.Web: contains domainservices for monitors
Both the Workflow.Web and Monitor.Web project uses a Enumeration (SalesChoice) type defined in the Common.Web project as return value on a DomainService.
So far the Web side of this story. We continue with the client part, which consists of two projects:
Workflow.UI: Contains the RIA connection with the Workflow.Web
Monitor.UI: Contains the RIA link with the Monitor.Web
Now my problem (finally :) ). In the Workflow.UI project I need to use information from the Monitor.UI project, so I added a reference between those two. When I build the project I get an error:
Warning as Error: The type 'MyProject.SalesChoice' in 'Generated_Code\Workflow.Web.g.cs' conflicts with the imported type 'MyProject.SalesChoice' in 'Monitor.UI.dll'.
It is pretty easy to explain why it's going wrong, but I'm looking for a solution. Maybe my whole approach with a shared Common.Web project is not possible or the best idea?
(sorry for my bad english)
On this cases I prefer to use a Portable Class Library. Define your enum on that project and add it as reference to all projects where you need it.

How to configure Silverlight + CSLA Data Portal?

I am new to Silverlight and CSLA and I need to get an example project working. I have both Lhotka's 2008 book on CSLA, as well as the Silverlight ebook + example project it comes with.
I thought it would be fairly simple to create a Silverlight 5 MVVM Light project that grabs a CSLA 4.3 object through the Data Portal (data portal/channel adapter configured to use WCF) but can't get a CSLA object back from the Server.
NOTE: If I take CSLA out of the equation and just use Linq to SQL or Entity Framework and a WCF RIA Service call I can grab objects from the server and display them in silverlight just fine, but as I can't use that on this project I must get CSLA to work.
My steps:
Created a Silverlight Business Application - get a MyProject (SL) and a MyProject.Web (WCF)
Added a service to the .Web project
<% #ServiceHost Service="Csla.Server.Hosts.Silverlight.WcfPortal" %>
.
Referenced the Service in my App.xaml Application_Startup method in the SL project
Csla.DataPortalClient.WcfProxy.DefaultUrl = "http://localhost:14790/Services/MyTestCslaSilverlightWcfService.svc";
.
Added a simple CSLA Business layer project (MyProject.CSLA) that has one set of test objects (MyMobileObjItem.cs, MyMobileObjItemList.cs)
Added two more projects (MyProject.CSLA.Client and MyProject.CSLA.Server). The .Client project is a Silverlight class library, the .Server is a class library. I then linked all my CSLA objects (add existing reference, add as link) plus all necessary references (csla/csla silverlight dlls). On MyProject I add a reference the .Client project and on MyProject.Web I add a reference to the .Server project.
Now I should have a working project, and want to get an item or a list of items back from the server. In my main ViewModel in the constructor I have tried two different things. When I use
MyMobileObjItemList.GetAllAsync(HandleReturnedArgs);
the callback method EventArgs have an error "System.IO.FileNotFoundException: Could not load file or assembly "MyProject.CSLA.Client". I find this weird since the Silverlight app has a reference to this project, and the MyProject.Web shouldn't need the .Client reference since it has the .Server reference.
When I use
DataPortal<MyMobileObjItemList> dp = new DataPortal<MyMobileObjItemList>();
dp.FetchCompleted += HandleReturnedArgs;
dp.BeginFetch();
the callback method EventArgs have an error "System.InvalidOperationException: Object type or assembly could not be loaded (MyProject.CSLA.MyMobileObjItemList, MyProject.CSLA.Client".
I am not sure where either of these errors are happening (on the client or server?) Since it is a Csla.DataPortalException I assume it is a server error.
I am not sure how to do a simple call or if this is the correct way of going about things as all the examples I can find don't do it this way and seem unclear to me.
I know this is a lot of pieces to fit together and it may be hard to concisely give an answer, but I really would appreciate help (code, link to download example etc.)
QUESTIONS:
Is there a simple example of Silverlight MVVM Light project that calls a remote data portal that grabs object(s) along with documentation of how to get it to work/how all pieces fit together? Again, I have the ebook Silverlight project, but that uses bxf and most of the data portal references the book has just says to see the other ebook on data portals (which I don't have - I would buy it but the site takes a couple days to allow access to the pdf. Really poor site). OR
Can someone explain what I am doing wrong?
To fix the error error I changed the assembly and default namespaces for my .Client and .Server projects to exactly match the .CSLA project (set in project properties)
See this forum discussion for more info

Type Redefinition With WSE Web Service Import

Consider the following Visual Studio project structure
ProjectA.csproj
AClass.cs
ProjectB.csproj
References
ProjectA
Web References
AWebService
AWebService.csproj
References
ProjectA
ReturnAClassViaWebService.asmx
The issue occurs when ProjectB adds the web reference to AWebService and automatically generates all the proxy code for accessing AWebService including a new implementation of AClass. Since all of our other code needs to use the AClass defined in ProjectA, we're forced to convert the AWebService.AClass returned from the service into something we can use.
We're currently considering two solutions, neither of which are ideal.
Manually editing the generated Reference.cs to remove new definitions of AClass
Serializing AWebService.AClass to a stream then deserializing to ProjectA.AClass
Does anyone have any better solutions? This seems like something common enough for other developers to have experienced it.
Ideally we would like to have the proxy code generated in ProjectB to reference ProjectA.AClass rather than generating a whole new implementation.
Our environment is VS 2008 using .NET 2.0.
I have had the same problem that you are describing and I have tried both of the options you specify without being entirely happy about either of them.
The reason we both have this issue is at least partly because the shared-library-between-consumer-and-provider-of-a-web-service-solution is in violation of accepted patterns and practices for web service design. On the consumer side, it should be sufficient to know the interface published in the WSDL.
Still, if you are prepared to accept a tight coupling between your web service provider and web service consumer and you know for certain that your current client will never be replaced by a different client (which might not be capable of referencing the shared library), then I understand why the proposed solution seems like a neat way to structure your app. IMPORTANT NOTE: Can we really honestly answer yes to both of these questions? Probably not.
To recap:
The issue appears when you have classes (e.g. a strongly typed dataset) defined in some sort of shared library (used on both client and server).
Some of your shared classes are used in the interface defined by your web service.
When the web reference is added there are proxy classes defined (for your shared classes) within the web reference namespace.
Due to the different namespaces the proxy class and its actual counterpart in the shared library are incompatible.
Here are four solutions that can be tried if you want to go ahead with the shared library setup:
Don't. Use the proxy class on the client side. This is how it is intendend to be done. It works fine unless you simultaneously want to leverage aspects of the shared library that are not exposed by the web service WSDL.
Implement or use a provided copy/duplication feature of the class (e.g. you could try to Merge() one strongly typed dataset into another). A Cast is obviosuly not possible, and the copy option is usually not a very good solution either since it tends to have undesirable side-effects. E.g. When you Merge a dataset into another, all the rows in the target dataset will be labeled as 'changed'. This could be resurrected with AcceptChanges(), but what if a couple of the received rows were actually changed.
Serialize everything - except for elementary data types - into strings (and back again on the consumer side). Loss of type safety is one important weakness of this approach.
Remove the explicit declaration of the shared class in Reference.cs and strip the namespace from the shared class wherever it is mentioned within Reference.cs. This is probably the best option. You get what you really wanted. The shared class is returned by the web service. The only irritating drawback with this solution is that your modifications to the reference.cs file is lost whenever you update your web reference. Trust me: It can be seriously annoying.
Here is a link to a similar discussion:
You can reuse existing referenced types between the client and service by clicking on the 'Advanced' button on the 'Add Service Reference' form. Make sure the 'Reuse types in referenced assemblies' checkbox is checked and when the service client is generated it should reuse all types from project A.
In past versions this has not always worked correctly and I've had to explicitly select the shared type assemblies by selecting the 'Reuse types in specified referenced assemblies' option and then checking the appropriate assemblies in the list box. However, I just tested this with VS 2008 SP1 and it appears to work as expected. Obviously, you need to make sure that the types that are being used by the service and client projects are both from project A.
Hope that this helps.
We encountered a similar problem with one of our projects. Because we had several dependencies, we ended up creating a circular reference because project 1 required objects from project 2, but project 2 could not be build before project 3, which relied on project 1 to be build.
To solve this problem, we extracted all the public standalone classes from both projects and placed them inside a single librarie. In the end we created something like this:
Framework.Objects
Framework.Interface
Framework.Implementation
WebService
The WebService would be linked to all projects in our case, whereas external parties would only be linking to the objects and interface classes to work with. The actuall implementation was coupled at runtime through reflection.
Hope this helps

Adding WCF Service Reference doesn't generate code

Scenario:
Web Site project under .NET 3.5
Visual Studio 2010
WCF Service reference
Problem:
I'm trying to extend a class marked with the DataContract attribute. I though the generated class was declared partial, so that i could easily extend it. I tried declaring a partial class within the same namespace with the same name, but it doesn't seem to recognize what class it's extending. I tried locating the generated code file (Reference.cs) which i thought existed after reading this article inside the reference folder, but it wasn't there. When trying to navigate to the class's definition, i found out it was in a compiled library, and the biggest problem is that it wasn't declared as partial.
Question:
Is this difference related to the fact that i'm using a Web Site and not a Web Project?
If so, is there a way that i could make the code generator (which also seems to compile the generated code) to declare class as partial?
Yes there is a way you can declare your DataContract classes as Partial.
For this you'd want to use the DTO pattern. Basically this means defining "shared" Classes in a different assembly, and having both the Service, and the App which consumes the Service, both reference the assembly with your common classes.
So for example your "DTOs" assembly might contain a DTO called "Product". Ok, so you make them Partial, and next you decorate Product, and which ever other Class with the WCF attributes, like DataContract, and DataMember etc.
Now, you reference you DTO assembly with you Service project, and your Web Project.
Now, when you go to your web project and click on "Add Service Reference", click on the "Advanced", and you'll notice you can enable an option to "resuse referenced assemblies". do that and you'll have full control over you DataContracts.
Empty client reference proxy classes can indeed be a most frustrating problem to solve.
I would recommend that you use the WCF Test Client or command line svcutil.exe. against the service - you can often get a much more detailed error description with these tools than with Visual Studio service reference wizard.
In my case the issues are invariably related to serialization or namespacing issues of the entity / graph - typically mismatched get and set on DataMember properties, missing KnownType on polymorphic entities, or circular references in the graph.
Partial shouldn't be a problem. Just make sure that any additional properties that you want serialized are marked as DataMember.
If all else fails, would recommend that you run a serialization / deserialization unit test against your entity / entity graph.

Categories

Resources