Adding WCF Service References to multiple projects - c#

A couple of very basic questions. I am new to WCF and I am building an application which has a Service Project, A Web Application project and a few Class library projects which I use for Business logic, etc.
I am hosting the WCF locally on my IIS and trying to add service references to the projects.
Question 1. When adding references, should I add a service reference to each project separately or is there a way I can share the same Service reference across the projects?
The reason I ask is because if I add separate references, each reference gets it own namespace, and when I have to pass the same object between the projects, I get an InvalidCastException because each ServiceClient has a different namespace.
Example -
Site.Business.XDataService.XDataServiceClient().GetItem()
is not the same as
Site.Web.XDataService.XDataServiceClient().GetItem()
Question 2. I specified the address of the local service in the class that implements the Service interface as below -
[ServiceBehavior(Namespace = "http://localhost:801/XDataService.svc", IncludeExceptionDetailInFaults = true)]
This doesn't seem right. If I move my code to a different/live environment, I would obviously have to change this part again and recompile. Where can I specify this (Web.Config?) so that I can change this address without having to rebuild my app?
Appreciate any kind of insight.
Thanks!

In answer to the first question, you can put the service reference in its own project and reference that project in all the other projects that need to access that service.
Basically all the service reference is is a lump of .NET code - namespace, class, etc.
Better yet (!) for a WCF service you also get an interface thrown in for free (more or less the same interface that you defined for your service) so you can do nice things in terms of dependency injection making testing etc easier.

First question - the service is just like any other code. For example, database access code. Should you put that in every project that needs to access your database? No - you should put it in a project which those other projects can reference.
As for your second question, you're specifying a namespace but I expect you think you're specifying a service endpoint address. The namespace is just like a C# code namespace - it essentially provides further identification and clarity in the event that you have multiple objects with the same name. Normally you'd use a namespace like http://mywebsite.com/MyService/VersionNumberIfRequired or similar.
The address itself is specified in configuration. The address will change depending on environment / deployment location - the namespace shouldn't.

Related

Added service reference appears in a completely different namespace

So as headline says .. I wrote a service for project A - then I needed a similar service for project B so instead of inventing and building the wheel a second time, I copied the service, edited every name and reference to point to project B.. but to my surprise when adding the service reference it still is seen in the namespace of project A instead of Project B ...
How can I change that behaviour?
Do you have a wrong understanding of adding a service reference, please refer to this link to add a service reference to the application. It is very convenient to add service references for different applications. Only the url of the service is needed to establish a service reference. Or use channelfactory to call the service.
In case somebody else stumbled upon the same ..
the solution is pretty simple - just go to the service's properties in VS - check the AssemblyName and Standard Namespace on the "Application" page of said properties - I just found that those 2 fields referenced the old service name and namespace .. after changing them, all came together as wanted.
And #Theobald - certainly I've created quite a few services but this is the single one that was "too identical" to bother to invent it a second time ...

Does a webservice is a standalone or can use outside classes

Can a web service use other classes that I have in a project or should it be standalone and use only it's own methods?
Thanks !
Does a web service can use other classes that I have in the project ?
YES it can. You can also return your custom class object, after serialization. Its very unusual that you would see webservice interacting with primitive types only (internally).
You can create instances of other classes and use them to perform work.
Any class in the same project or a referenced project should be usable, subject to the usual access modifiers.
You'll either need to include a using statement. Following example assumes you want to use SomeClass which resides in MyAssembly.SomeLibrary:-
using MyAssembly.SomeLibrary;
// in code block somewhere
var thing = new SomeClass();
or fully qualify the name of the class.
var thing = new MyAssembly.SomeLibrary.SomeClass();
It sounds like you are asking in terms of best practice rather than "is this technically possible". The answer depends on the class you want to use I suppose, but in general it is acceptable to use any other classes or libraries you want in a web service as this will not affect the client being able to consume the service (i.e. using LibraryA on the service side does not mean client 1 has to also have LibraryA installed to use your service).
It is possible to reuse those classes service side (in Visual Studio this is done by ticking the "Reuse types in referenced assemblies" box when you configure a service reference and then adding a reference to the appropriate project / dll), but I would generally advise against it as it can confuse matters - not all clients will have access to those dlls when consuming your service.

WCF Multiple Services with DataContracts as Parameters C#

I have multiple DataContracts and the same number of WCF Services to manage methods for each one. I have a specific [DataContract] called User that I use as paramenter in every other service, for example: ListCompany(User, CompanyId).
When a make a service referece to the WCF service, Company, it has a [DataContract] User too like Company.User which is different from the original User. Is there any way to solve this?
Logically Same DataContract, Used in Multiple Services
You are probably adding service references in the usual way for a WCF service client using the Add Service Reference... menu option. When you do that, a Reference.cs file will be generated for each service, and each service will have a different namespace. However, since you're sharing contracts across services, you need to click the Advanced... button on the Add Service Reference dialog and make sure the Reuse types in referenced assemblies is checked and (easiest) make sure Reuse types in all referenced assemblies is checked.
Now, that will not work if you don't actually have normal project or assembly references to the assemblies that contain those [DataContract] classes. So, add those references. If those classes are mixed into your server-side implementation, you will need to move them to their own assemblies and reference them on both the client and server.
Logically Different DataContract, Used in Multilpe Services
If you really have two different types of users (i.e. two different contracts) where you are using one contract for one service client and one contract for another service client, you should make sure Reuse types in referenced assemblies is not checked, and make sure that each service reference is in a different namespace.
An alternative is using a different name for each when declaring them:
[DataContract(Name = "User"]
public class User { ... }
[DataContract(Name = "CompanyUser")]
public class User { .... }
The code above assumes each User class is in a different server-side namespace, possibly different assembly as well.
I would suggest that you should look into a better way to use your WCF services that adding service references. This golden article describes how you can share the data contracts between all your solutions, and make use of them by using Chanel factories, without having VS generate loads of code for you. http://www.netfxharmonics.com/2008/11/understanding-wcf-services-in-silverlight-2
It might seem like a lot to take in, but it's full of really useful tips, including Service Access without magic which goes like this:
Now we may turn our attention to the client application. To begin,
let me start off by reminding everyone that you shouldn't ever use
"Add Service Reference" in Visual Studio for magical service client
creation. The code is incredibly verbose, hard to manageable, edits
are prone to being overwritten, and it's almost always used as an
excuse to not actually learn WCF. There are few things worse than
having to deal with people who thing they know a product simply
because they know how to use a mouse. There are reasons why Juval
Lowy, in all his books and talks, repeatedly tells people to avoid
using this flawed feature. Fortunately, as professionals, we have the
ability to understand how to do things without magic.
As I've mentioned many times already, WCF relies on the concept of the
ABC. We've seen how we configure a WCF host by creating an endpoint
specifying an address, binding and contract. As it turns out, this is
all that's required on the client side as well. For both .NET and
Silverlight, you merge an address and a binding with a contract in a
channel factory to create a channel. This isn't just fancy conceptual
architect speak, this is exactly what your code would look like (the
sign of really good architecture!) Below is the .NET version of what
I mean:
BasicHttpBinding basicHttpBinding = new BasicHttpBinding();
EndpointAddress endpointAddress = new EndpointAddress("http://localhost:1003/Person.svc");
IPersonService personService = new ChannelFactory<IPersonService>(basicHttpBinding, endpointAddress).CreateChannel();
//+
Person person = personService.GetPersonData("F488D20B-FC27-4631-9FB9-83AF616AB5A6");
Well worth a read.

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

Class Libraries, Silverlight and Webservices

I have a Silverlight Class Library that I want to use in both my Silverlight and my WebService project.
I am able to create and reference the Library in both projects without any problems, but when I try to use any of the classes in the Library on the Silerlight project, I get an ambiguous reference error between my Library and the Asmx Webservice (apparently, the silverlight project believes that the classes in the class library exist in the webservice).
How can I correct this issue? I have tried rebuilding and cleaning, but it does not seem to work. Can anyone help?
Sounds like the objects you are passing to Silverlight, via the WCF service, are the same objects in your class library. In that case the generated web-reference objects will be given the same names. Linking with the library will then give you 2 sets of objects with the same names.
If you install RIA services, once feature is the ability to share code between client and server by simply adding ".shared" in the class filenames before the extensions. ASMX services are so last century :)
if you don't want to learn the RIA services way of sharing objects across the great-web-divide (which I would recommend), you need to separate the data objects from the functionality you actually want to share client and server side.
To give more specific advice on your current set-up I would need to see more about how it is structured.
A technique you can use is aliasing your using statements:
using MyNameSpace = My.Name.Space;
using MyWebService = My.Web.Service;
Then access all of your objects with these aliases to remove the ambiguities.

Categories

Resources