URL: http://wcftutorial.net/Introduction-to-WCF.aspx
Question 1:
Above tutorial mentions a Tip:-
a. Define the service in Class library and refer the class library in Host project. Don’t use service class in host project.
b. Always create the service with Interface->Implementation format, mention the contract in Interface.
c. Define the service in Class library and refer the class library in Host project. Don’t use service class in host project.
Question: Does the good practice suggest to create another class library rather then the existing IService1.cs and Service1.svc? Can anyone here give me an example of what author is trying to say in the above points?
Question 2:
When I create a new WCF application it has got IService1.cs and Service1.svc. All the implementation I have coded under Service1.svc.cs
Under the IService1.cs there is Service and Operation Contract, data contract (What is purpose of data contract here? can I delete it off?).
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
// TODO: Add your service operations here
}
// Use a data contract as illustrated in the sample below to add composite types to service operations.
[DataContract]
public class CompositeType
{
bool boolValue = true;
string stringValue = "Hello ";
[DataMember]
public bool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}
[DataMember]
public string StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
}
First of all, I would like to suggest you reading the basics of WCF in a book "Learning WCF" from Michele Leroux Bustamante, if you have an option to get it - the tutorial you are linking to was too chaotic by my opinion (I was reading it some time ago too)
Question 1: The thing is, that you should define 2 projects - 1 will contain host of the service and second will contain definition/implementation of that service. See picture below:
In ServiceHost, I ussualy have only main entry point, which launches the host. In ServiceLibrary (you can choose whatever name suits you) I have the service interface and implementation. Also, please notice that in ServiceHost, I have referenced ServiceLibrary.
Question2: Simply said: DataContracts are used when you are working with your custom objects over WCF. Lets say you want to get information about "Person" from you service. You can either define for example 3 OperationContracs - first would return name (string), second one age of that person (int) and third one telephone number (int).
But this is not the way you should proceed - you should return Person object from service (in your case, you have "CompositeType"). For that, you need to mark the class with [DataContract] attribute and all the information you want to exchange with [DataMember] attribute.
Of course you dont need to have the definition of "CompositeType" in IService - you can create new class in your project, name it "CompositeType" and mark it as [DataContract].
Is it more clear?
Answer of Question 1
Yes you need to create a separate class library for your service and a separate host project.See the following
You need to create something like this. Add Reference of AngService in AngServiceHost Application.
AngServiceHost Application is WCF Application. Delete the Service1.cs and IService1.cs
Add following lines in Service1.svc in AngServiceHost
<%# ServiceHost Language="C#" Debug="true" Service="AngService.ILogin" %>
Answer of Question 2
Whatever you have coded in .svc.cs file should go in the service class library, not in the host application.
Understand that the .svc file is used for hosting. You can reference the source of the service in this .svc file. In my example the dll of AngService (the class library) is added in AngServiceHost(the host application). This dll contains the actual code. You need to do something similar to this.
Related
I have several WCF services that use the same dataContracts to interchange data between them.
Can I have a sort of Metadata Endpoint for centralizing the management of all this schemas?
When creating a new WCF service, how can i make it to load the schemas from the Metadata Endpoint (instead of redefining them) to use inside its operationContracts?
Thanks!
As I said in the comment, I'm not sure I understand your question (at least with regards to wanting a metadata endpoint), but it sounds like you want to have the ability to reuse existing data contracts in multiple different services.
The easiest way to do that is to put the data contracts in a separate assembly (class library - DLL), and then have the services reference that assembly - they don't have to be defined inside the service itself.
Here's a trivial example (code is for illustration only, not intended to actually do anything or be a complete sample):
MyDataContracts assembly
namespace MyDataContracts
{
[DataContract]
public class DataContract1
{
}
[DataContract]
public class DataContract2
{
}
}
MyService1 assembly
using MyDataContracts;
namespace MyService1
{
[ServiceContract]
public interface IMyService1
{
[OperationContract]
DataContract1 GetSomeData(string someParm);
}
}
MyService2 assembly
using MyDataContracts;
namespace MyService2
{
[ServiceContract]
public interface IMyService2
{
[OperationContract]
void SendSomeData(DataContract1 dc);
[OperationContract]
DataContract2 GetSomeOtherData(int parm);
}
}
Of course, each of the WCF service projects will need to include a reference to the MyDataContracts assembly as well.
Now whenever you create a new service, you simply add a reference to the MyDataContracts.dll and you can reuse your data contracts in it.
I am trying to add a web reference to a WCF service. On browsing to that service through the project explorer, the new function added to that service is not getting listed.
This is my code in the *.svc file
public class Service1 : IService1
{
public string GetData(int value){;}
public CompositeType GetDataUsingDataContract(CompositeType composite){;}
public double Undo(double value, bool isPound){;}
}
Now, while referencing my service as UndoService, my Undo method is not showing up. The following show up by intellisense:
(class) CompositeType
(interface) Service1
(interface) Service1Channel
(class) Service1Client
This might be a naive question, but I am not able to proceed. I probably am missing something big here. Please help!
The Service1Client is your proxy class and have to instantiate that class to invoke the service methods.
var proxy = new Service1Client();
proxy.Undo(..)
You need to update the reference if you have added new functionality. You can do this by right clicking the existing reference entry and selecting update, this will download the updated service contract.
You most likely forgot to either add the method to your contract interface or to decorate the contract method with the [Operationcontract] attribute.
EDIT : I kinda misread the question, apply Mark answer before anything.
I have my service layer, entities and DTOS in a separeted assembly called CCL.Data
The problem:
All My application is referencing the service layer directly using interfaces and IoC.
For example, I have an interface in my CCL.Data assembly called ICustomerService it depends on ICustomerRepository that depends on MyContext. All my application is referencing ICustomerService to call its methods....... so far no problem.
So I created a WCF Project.... referencing CCL.Data in this project....
I create a new Service, but int this case below, I would need to change all points in my application that call ICustomerService to WCFCustomerServiceClient, does exists a better way without cause a big impact in my project?
[ServiceContract]
public interface IWCFCustomerService
{
[OperationContract]
CustomerDTO GetCustomerById(int id);
}
public class WCFCustomerService : IWCFCustomerService
{
ICustomerService _customerService;
public WCFCustomerService()
{
MyContext context = new MyContext();
ICustomerRepository customerRep = new CustomerRepository(context);
_customerService = new CustomerService(customerRep);
}
public CustomerDTO GetCustomerById(int id)
{
return _customerService.GetCustomerById(id);
}
}
Tks,
William
Do you need to redefine IWCFCustomerService in place of ICustomerService? Is it not possible just to add ServiceContract attributes to your original ICustomerService interface (they will just get ignored by non WCF code)? (Its true that this does give you a dependancy on ServiceModel - but I cant see a way out of that).
Note also that if you use a ServiceRefernce to generate proxy code then the code generated will include a your service interface in different namespace for use clientside. Its worth noting that your not abliged to use that version of the interface (which could be annoying if you have a proxy and not proxy implimentation) but can still use the org interface definition either from a dll or compiled into your client.
My understanding may be wrong, but I thought once you applied the correct attributes the DataContractSerializer would render fully-qualified instances back to the caller.
The code runs and the objects return. But oddly enough, once I look at the returned objects I noticed the namespacing disappeared and the object-hierarchy being exposed through the (web applications) service reference seems to become "flat" (somehow). Now, I expect this from a web-service…but not through WCF. Of course, my understanding of what WCF can do may be wrong.
...please keep in mind I'm still experimenting with all this.
So my questions are…
Q: Can I do something within the WCF Service to force the namespacing to render through the (service reference) data client proxy?
Q: Or perhaps, am I (merely) consuming the service incorrectly?
Q: Is this even possible?
The service code looks like…
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class DataService : IFishData
{
public C1FE GetC1FE(Int32 key)
{
//… more stuff here …
}
public Project GetProject(Int32 key)
{
//… more stuff here …
}
}
[ServiceContract]
[ServiceKnownType(typeof(wcfFISH.StateManagement.C1FE.New))]
[ServiceKnownType(typeof(wcfFISH.StateManagement.Project.New))]
public interface IFishData
{
[OperationContract]
C1FE GetC1FE(Int32 key);
[OperationContract]
Project GetProject(Int32 key);
}
[DataContract]
[KnownType(typeof(wcfFISH.StateManagement.ObjectState))]
public class Project
{
[DataMember]
public wcfFISH.StateManagement.ObjectState ObjectState { get; set; }
//… more stuff here …
}
[DataContract]
KnownType(typeof(wcfFISH.StateManagement.ObjectState))]
public class C1FE
{
[DataMember]
public wcfFISH.StateManagement.ObjectState ObjectState { get; set; }
//… more stuff here …
}
[DataContract(Namespace = "wcfFISH.StateManagement")]
[KnownType(typeof(wcfFISH.StateManagement.C1FE.New))]
[KnownType(typeof(wcfFISH.StateManagement.Project.New))]
public abstract class ObjectState
{
//… more stuff here …
}
[DataContract(Namespace = "wcfFISH.StateManagement.C1FE", Name="New")]
[KnownType(typeof(wcfFISH.StateManagement.ObjectState))]
public class New : ObjectState
{
//… more stuff here …
}
[DataContract(Namespace = "wcfFISH.StateManagement.Project", Name = "New")]
[KnownType(typeof(wcfFISH.StateManagement.ObjectState))]
public class New : ObjectState
{
//… more stuff here …
}
The web application code looks like…
public partial class Fish_Invite : BaseForm
{
protected void btnTest_Click(object sender, EventArgs e)
{
Project project = new Project();
project.Get(base.ProjectKey, base.AsOf);
mappers.Project mapProject = new mappers.Project();
srFish.Project fishProject = new srFish.Project();
srFish.FishDataClient fishService = new srFish.FishDataClient();
mapProject.MapTo(project, fishProject);
fishProject = fishService.AddProject(fishProject, IUser.UserName);
project = null;
}
}
In case I’m not being clear…
The issue arises in that the namespacing I expect to see (returned) is different from what is actually returned.
fishProject.ObjectState SHOULD look like...
srFish.StateManagement.Project.New
fishC1FE.ObjectState SHOULD look like...
srFish.StateManagement.C1FE.New
fishProject.ObjectState ACTUALLY looks like...
srFish.New1
fishC1FE.ObjectState ACTUALLY looks like...
srFish.New
OK - default behavior for a WCF Service is this:
you define your service contracts, operations, and data contract on the server (e.g. in namespace "Server.MyService")
once the service is up and running, on your client, you create a service reference
when doing so, what Visual Studio or svcutil.exe do, is interrogate that service for its metadata (description of service methods and data)
based on that metadata, the client side proxy is generated (namespace "Client.MyService") and it contains replicas of the service contract (the methods) and the data contract
Important: it contains replicas of those things! They look the same, and they serialize into the same XML format on the wire - but they are different - in different namespaces, most notably.
This is the very nature of WCF - all you do is exchange serialized messages between client and server - all that goes back and forth are textual messages. Nothing more - no object references, no remote object - nothing like that. Toss that out of your mind! :-)
If you control both ends of the wire, this can be a pain - if you need to change anything, you have to change it on the server side, update the client references and so forth.
So if you control both ends of the wire - both the server and the client - and they're both .NET based, you can do the following:
put your service contracts and your data contracts (only the contracts - no implementations!) into a separate assembly
from your service implementation, reference that contracts assembly
copy the contracts assembly to your client, and also reference it in your client project
Now, if you add the service reference, by default, the Add Service Reference function in Visual Studio will reuse existing types in referenced assemblies - so if you have referenced your common "Contracts" assembly, those types (in their full glory, including their namespace) will be reused - no additional copies will be created.
That way, you can create a single, shared contracts assembly used by both the server side code, as well as your client, and you don't have to mess with any duplication of data structures. But again: that only works if you are in control of both ends of the wire, and both are .NET
I have two ServiceContracts implemented as interfaces. I want to export the metadata for only one of them. The trick is that both interfaces are implemented by the same class. Therefore, I don't think that I can use /excludeTypes. Please include example syntax when answering. Thanks!
EDIT: A co-worker recently asked me why this is necessary. The reason why is that the first ServiceContract is for a REST service, which it doesn't make sense to export metadata for. So I get two wsdl and xsd files generated, distinguishable only because the second filename is appended with "1". This makes tooling difficult, and adds more clutter to the output directory.
I've added a bounty to try and generate interest in this question.
I created a Service Contract class implementing 2 Interfaces like you described.
namespace NS
{
[ServiceContract]
public interface IREST
{
[OperationContract]
string WorldHello(string name);
}
[ServiceContract]
public interface IInterface
{
[OperationContract]
string HelloWorld(string name);
}
public class CI2 : IREST, IInterface
{
public string WorldHello(string name)
{
return "World Hello: " + name;
}
public string HelloWorld(string name)
{
return "Hello World: " + name;
}
}
}
when running svcutil normally, I get a wsdl with methods from the 2 interfaces
when I run svcutil with /excludeType:IREST for example, I get only IInterface methods.
svcutil /excludeType:NS.IREST ci2service.exe
are you using the same configuration? In that case /excludeType works.