What is the correct way to solve the ambiguous reference issue in WCF services? - silverlight

Project Structure
I have a silverlight project SLProj, that references a silverlight class library project called ServiceClients. ServiceClients has two wcf service references, Svc1.svc and Svc2.svc. Both Svc1.svc and Svc2.svc are in two different WCF projects which use the same set of DataContracts which are again in a different class library project called MyDataContracts.dll.
Problem description
Now in my ServiceClients project I get an ambiguous reference issue when I need to use a datacontract class which is present in both the service references. If this were a winforms or webforms project, I could reference the MyDataContracts.dll and reuse the common types. But since, this MyDataContracts.dll was built using a non silverlight class library, it can't be referenced in the silverlight project
Workaround...
I am not sure if this below is the best method to go about taking care of this issue. Can anybody let me know if there is a cleaner way to solve this problem, or is this the best way we have so far?
create a single service reference.
click the 'show all files' button in the solution explorer
drill into the service reference and find Reference.svcmap and open it
find the MetadataSources section
add a second line to include the address to your second service. for example:
MetadataSource Address="http://address1.svc" Protocol="http" SourceId="1"
MetadataSource Address="http://address2.svc" Protocol="http" SourceId="2"
save, close, and update service reference.

Use Automapper
Map the DataContracts with AutoMapper.
You will have to invest some time in understanding AutoMapper and reworking your application. Also AutoMapper adds overhead because all data objects will be mapped. But first you will have a clean solution without hacks and second you gain a decoupled and simple data object layer just for your client. Once done you can forget the mapping but you stay flexible for future changes.
If you never have worked with Automapper it's important to play around with it before starting. Automapper is special and needs some time to familiarise with it.
So there. These are the rough steps:
1. Create a subdirectory and sub-namespace Data and copy the DataContracts. Remove the attributes and properties your client doesn't need because these mapped classes live only in your client. You can also change some types or flatten some complex properties.
2. Create an AutoMapperInit.cs like described at Automapper (read the Getting Started Guide). Use the conflicting references like this:
using ref1 = YourProjectServiceReference1;
using ref2 = YourProjectServiceReference2;
3. Wrap the service client like this:
Example GetExample() {
return AutoMapper.Map<ref1.Example, Example>(ref1.YourService.GetExample());
}
The wrapper also needs the same using directives as in step 2.
4. In this wrapper add a static initializer like this (assuming your wrapper class is called Wrapper):
static Wrapper() {
AutoMapperInit.CreateMaps();
}
5. Omit service references in the client and use using YourClient.Data;, the namespace you created in step 1.
Your client is now decoupled from the service and you don't have conflicts anymore.
Disclaimer: I am not affiliated with AutoMapper. I just used it in a project with a similar problem and am happy with it and wanted to share my experience.

Your workaround is actually quite OK. We've used it in several projects like this with 3 service references. It is actually a workaround for the IDE which for some reason only allows to select one service to create a service reference at a time.
Another thing you could try-out is to multi-target your shared contract to .NET and Silverlight, using the same codebase. Details on how to do such thing is described in http://10rem.net/blog/2009/07/13/sharing-entities-between-wcf-and-silverlight. Might be more work but feel less hacky.

Related

Adding WebAPI to Composite-C1

I am really impressed with CompositeC1 and the ability to add data types on the fly, reference other data types with a foreign key relationship, etc. The built in functions are also really handy.
Ideally, I could create a separate Web API project that would be able to use all of the functions that are generated on the fly in CompositeC1 and expose them out as REST services.
Should I do this as a separate project referencing the dll's in CompositeC1's bin directory? Those dll's are regenerated each time a custom data type is altered... would that cause an issue?
I just wrote a post tonight that I think answer the question.
http://www.s-innovations.dk/Blog/2013/06/25/Mobile-Services-for-Composite-C1--Idea-Creation
I make an API by tapping into the C1 System and get my data from there. No need to worry about dlls being generated and such.
But you can create your own API in a seperate dll also. You can see from my post the basic steps of getting an API up and running.
You could get a problem if you make a WebAPI that exposes something that a user deletes in the console, then your dll breaks? The idea with my project is to make it dynamic expose types configured from within the console. So if someone deletes a type, then it also get removed from my API.

Generating Silverlight service reference - how to tell what is causing proxy classes to be generated

I have a large object structure that I'm wanting to share between a .Net4 backend and a Silverlight 5 front end. I've created two class library projects of the appropriate type, and have my object structure implemented in the .Net library, and linked into the SL library. On the Silverlight client side I am referencing the Silverlight class library. When I generate the service reference I have checked the option to "Reuse types in referenced assemblies". However when I generate the service reference I am finding that types that are in referenced assemblies are still being generated. It is only certain types, and appears to be largely collection types (attributed with <CollectionDataContract>).
I have a main object that has many properties which are generally either List<MyTypeA> or in some cases they are MyListTypeB, where MyListTypeB inherits from List<MyTypeB>. It seems to be the classes similar to MyListTypeB that are causing the proxies to be generated. These are all attributed with <CollectionDataContract> and have a default constructor.
I also find that even though the project where I am adding the service reference to has a reference to the other SL project containing the entities, when I update the service a new reference directly to the dll is also being added to the project. I'm not sure why this is happening, or if it is causing confusion in the service proxy generation
Is there any way to tell what classes/properties are causing the service generation to generate proxy classes? Or is it a case of trial and error having to comment out attributes until they aren't generated and hone in on the problem class?
I have now found out about the use of the svcmap file, and updating the CollecitonMappings elements to include my collection types, described here:
http://mostlydevelopers.com/blog/post/2009/12/14/Configure-WCF-Service-ndash3b-Reuse-Collection-Types-Issue.aspx
It seems a little unusual that the svcmap functionality is so undocumented.
I was able to add an entry int he svcmap file similar to the following:
<CollectionMappings>
<CollectionMapping TypeName="MyNamespace.MyType" Category="List" />
</CollectionMappings>
And then when I updated the service reference the proxy collections are not generated.

How to implement DI using DbContext in Windows Form

I have a class running in a winforms app which uses EF Code First. The DbContext is created via DI through the class constructor. All works well.
The problem is the data being referenced is also being modified via a web site, using the same DI pattern with EF Code First, and the data changes are not being reflected in the context instance in the winforms app.
I can solve this by recreating the DbContext object in winforms every time I access it, but seems to be more of a service location pattern to me?
Is there a true DI technique to achieve this?
Or should I remove the context from the DI and use service location?
Were you not happy with the answer to your other question (http://stackoverflow.com/questions/7657643/how-to-force-ef-code-first-to-query-the-database) which suggested using Detach, AsNoTracking or Overwrite Changes?
1) Maybe you could pass an interface that has the ability to create a DbContext, instead of the context itself.
using(var context = _contextFactory.Create()) {
var entity = from table in context.Blah...;
}
The Create method could either create the concrete class itself (defeating the DI pattern a bit), or use service location to have one created for it. Not that nice, but it's better than embedding service location calls everywhere and still means you're controlling the lifecycle yourself.
2) Change the WinForm to read from a webservice run by the website, effectively similar to disabling caching.
3) Deep in the heart of MVC (well not really that deep) it is referencing the DI container directly and using it as a service locator to pass as arguments for newly created objects. Technically you could do something similar in WinForms, but it would need you to split your application up into little chunks (controllers) that don't have a very long lifetime. Maybe it's worth looking at some MVC/MVP frameworks for WinForms, although I found myself cringing at most I saw after a quick google.
The problem is the data being referenced is also being modified via a web site, using the same DI pattern with EF Code First, and the data changes are not being reflected in the context instance in the winforms app.
This is a problem with your expectations.
If your web service and window forms app are in separate processes, they won't share in-memory data.
If you want to sync their in-memory data, simply re-query in one context after committing to the database in the other. This is the same as trying to share data between different SQL connections.
I can solve this by recreating the DbContext object in winforms every time I access it, but seems to be more of a service location pattern to me?
If you want to recreate the DbContext repeatedly, you could use an abstract factory to allow manual re-creation of the object, yet allow you to inject the specific implementation into the factory.
This is not (necessarily) the Service Locator pattern, and you would have to ensure that you manually dispose your DbContext instances. I'd give you some example code, but different DI containers have totally different ways of accomplishing a factory pattern.
Or you could simply make sure that you commit your data on the web service side, and re-query the data on the WinForms app side.

WCF from Silverlight without using Add Service Reference

David Betz describes in his article how to create reference to WCF without using "Add Service Reference" option:
http://www.netfxharmonics.com/2008/11/Understanding-WCF-Services-in-Silverlight-2
Once WCF service is created, these are the statements within the silverlight:
BasicHttpBinding basicHttpBinding = new BasicHttpBinding();
EndpointAddress endpointAddress = new EndpointAddress("http://localhost:1003/Person.svc");
IPersonService personService = new ChannelFactory<IPersonService>(basicHttpBinding, endpointAddress).CreateChannel();
...
How does one references the types (such as IPersonService interface) created in WCF from Silverlight when I do not use "Add Service Reference" to buid proxies?
Idea is to reference assemblies that contain WCF data contracts in silverlight application, and to do that you need to fool VS so it thinks assembly is a SL assembly, he describes this in detail here
http://www.netfxharmonics.com/2008/12/Reusing-NET-Assemblies-in-Silverlight
and its not so easy, here is what needs to be done
Just use the same ILDasm/Edit/ILAsm
procedure already mentioned to tell
the assembly to use the appropriate
Silverlight assemblies instead of the
.NET assemblies. This is an extremely
simple procedure consisting of nothing
more than a replace, a procedure that
could easily be automated with very
minimal effort. It shouldn't take you
much time at all to write a simple
.NET application to do this for you.
It would just be a simple .NET to
Silverlight converter and validator
(to test for assemblies not supported
in Silverlight). Put that application
in your Post Build Events (one of the
top 5 greatest features of Visual
Studio!) and you're done. No special
binary hex value searching necessary.
All you're doing is changing two well
documented settings (the public key
token and version).
Second solution is a file level solution , you use add link option on files that contain your required data contracts implementations to SL and make sure they only contain types that allow to build SL and dont reference a lot of external assemblies , usually those conditions should be met for WCF services & data contracts.
I can write more but it would be just the copy paste from that link
You also have to split all methods declaration in you IPersonService according to Async pattern (BeginXXX/EndXXX) since Silverlight supports only asyncronous WCF (even in background threads).
As a help to do this, you may add Service Reference, then copy generated IPersonService (all methods will be decoupled) from Reference.cs. Then you may remove the reference.
However, if your service contract is often changed, you have to repeat Add-Service procedure again, and starting from this, I would say, it's easier just use Add-Service-Reference feature, rather than sharing the contract with your app server.
Only one thing that I would like detect. Often you need in namespaces with more complex support of NET within your WCF service. Therefore you must have real reasons to reference to Silverlight subset within your WCF service (or service library). There are many ways to
use so named traditional ways by Add Service Reference. They are presented in good article enter link description here.

Reusing service proxies

I have a set of webservices that I connect to using Silverlight Client. I use proxies generated by "Add service reference" or SLSVCUTIL.exe tool to connect to this service. So far, I have only used one single service. Now I want to use another service on the same server.
The problem is that, first service generated set of proxy classes for me, and second service will reuse the same set of classes (plus extra services/classes), e.g.
CustomerService.SaveCustomer(Customer customer);
OrderService.CheckCustomerLevel(Customer customer);
The problem is when I add reference to the second service, I can not reuse the same namespace for the second one (VS error), and when I use a different namespace, the generated classes, although are essentially the same, reside in different namespace, hence different and I end up with two Customer classes in two different namespaces.
Anyway around this? I just neeed to have two set of services, reusing the Customer class. I have already tried "reuse types in assembly / all assemblies" check mark when generating proxy classes, but it seems to have no effect.
any help is greatly appreciated.
I've run into this problem before, and the only solution I could come up with was to combine both web services into a single web service. This seems to be a limitation of the Add Service References/SLSvcUtil way of doing things.
If you're using Silverlight 4, you could conceivably try Silverlight/.NET assembly sharing to get around this (though I haven't tried it myself). In other words, compile the assembly that contains your data transfer objects in Silverlight, and then share it with the .NET/WCF back-end. That way, if you choose "Reuse types in assemblies", it would (in theory) actually re-use the existing Silverlight types for both service references.

Resources