Where do data structures belong in a WCF application?
Say I have a web project which uses a WCF service for behind-the-scenes processing, and an MVC 2 project handling web-requests (I guess this wil开发者_开发知识库l be the WCF client). The WCF service generates data and deals with pre-generated data (the processing will likely happen asynchronously). These two things are separate projects in the same solution in visual studio.
Now, I'm not sure where to put the data structures representing stuff that the service generates, and stuff that the client needs to process and send to users' browsers. Currently they're all in the service's interface (endpoint interface? Not sure what it's called exactly) marked with [DataContract]
(not sure what that does yet). But, since the MVC app is in a separate project, I'd have to re-define all the data structures there -- is that necessary? Should I be putting these structures elsewhere in the solution? The interface is getting pretty full of class definitions -- am I able to make some sort of shared resource containing the shared data structures between the projects? What about the [DataContract]
part -- do I still need to stuff that in the interface somehow if the classes are defined somewhere else?
Apologies if I'm not quite making sense or being very vague. I've never used these Microsoft technologies before so I'm still pretty lost. I'm just learning as I go.
I like to structure my WCF solutions like this:
Contracts (class library)
Contains all the service, operations, fault, and data contracts. Can be shared between server and client in a pure .NET-to-.NET scenario. This is where you would put your data structure classes, so that all the projects in your ecosystem can use this.
Service implementation (class library)
Contains the code to implement the services, and any support/helper methods needed to achieve this. Nothing else.
Service host(s) (optional - can be Winforms, Console App, NT Service)
Contains service host(s) for debugging/testing, or possibly also for production.
This basically gives me the server-side of things.
On the client side:
Client proxies (class library)
I like to package my client proxies into a separate class library, so that they can be reused by multiple actual client apps. This can be done using svcutil or "Add Service Reference" and manually tweaking the resulting horrible app.config's, or by doing manual implementation of client proxies (when sharing the contracts assembly) using ClientBase<T>
or ChannelFactory<T>
constructs.
1-n actual clients (any type of app)
Will typically only reference the client proxies assembly, or maybe the contracts assembly, too, if it's being shared. This can be ASP.NET, WPF, Winforms, console app, other services - you name it.
That way; I have a nice and clean layout, I use it consistently over and over again, and I really think this has made my code cleaner and easier to maintain.
This was inspired by Miguel Castro's Extreme WCF screen cast on DotNet Rocks TV with Carl Franklin - highly recommended screen cast !
Put your data objects in another, separate project (select Class Library when creating it) and reference them from both WCF and MVC2 (duplication aside, I don't think it will be possible to get it to work otherwise).
[DataContract]
has to be used to decorate the data object classes, no matter where they are.
I am not sure what you mean when saying "What about the [DataContract] part -- do I still need to stuff that in the interface somehow"... can you provide some sample code?
For reference, here's some code from a project I worked on in the past:
This is in project Server.Contracts
:
namespace Server.Contracts.DataContracts.Mapped
{
using System;
using System.Runtime.Serialization;
[DataContract]
public class ConfigSetting : BindableDataContract
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string Value { get; set; }
[DataMember]
public DateTime ModifiedOn { get; set; }
public override object Clone()
{
return new ConfigSetting
{
ModifiedOn = this.ModifiedOn,
Name = this.Name,
Value = this.Value,
};
}
}
}
This is also in Server.Contracts
:
namespace Server.Contracts.ServiceContracts
{
using System;
using System.Net.Security;
using System.ServiceModel;
using Common.Constants.ServiceModel;
using Common.LogClient;
/// <summary>
/// Interface that defines the log service contract.
/// </summary>
[ServiceContract(
Name = ServiceContract.LogServiceName,
Namespace = ServiceContract.LogServiceNamespace,
ProtectionLevel = ProtectionLevel.None,
SessionMode = SessionMode.NotAllowed)]
public interface ILogService
{
[OperationContract(Name = "Deferred", IsOneWay = true)]
void Deferred(LogSeverity severity, DateTime eventTimeUtc, string actor,
uint? deviceId, string message, string stackTrace);
}
}
This project is referenced from these two other projects, among others:
- Client
- Server.Implementation (where e.g.
ILogService
is implemented)
精彩评论