I was looking an answer for this but I couln't find it. As you know, the NServiceBus library came with a sample that's call WCF Integration. It has an interface that the Server exposes as a WCF service, right? This interface has only one method inside. My idea is to have more than one method inside that interface, is this possible?
I have my own project, in which I have my interface with more than one method and my idea is that this WCF Service to have a method similar to "Process" from the sample, that publish messages.
Code:
[ServiceContract]
public interface ICancelOrderService
{
[OperationContract(Action = "http://tempuri.org/IWcfServiceOf_CancelOrder_ErrorCodes/Process", ReplyAction = "http://tempuri.org/IWcfServiceOf_CancelOrder_ErrorCodes/ProcessResponse")]
ErrorCodes Process(CancelOrder request);
[OperationContract]
ErrorCodes HelloWorld(CancelOrder request);
}
public class CancelOrderService : WcfService<CancelOrder, ErrorCodes>{}
I trie to inherit from ICancelOrderService, but didn't work.
So, any suggestions? Thanks people...
Regards, Matias.
thanks for your soon response. Maybe my explanation wasn't clear enough. I have my Server that inherits from WcfService, but my idea is to have more than one OperationContract, one similar to Process, and the others ones commons Wcf OperationContract, that they won't interact with NSB.
[ServiceContract]
public interface ICancelOrderService
{
[OperationContract(Action = "http://tempuri.org/IWcfServiceOf_CancelOrder_ErrorCodes/Process", ReplyAction = "http://tempuri.org/IWcfServiceOf_CancelOrder_ErrorCodes/ProcessResponse")]
ErrorCodes Process(CancelOrder request);
[OperationContract]
void HelloWorld(int var);
}
My code will be something like that. With your response I realize that the code of the first post was wrong.
So, is this possible, or I have to look other way to implement this?
Thanks, Matias
The WCF service that is exposed is only to get messages onto the bus. Once the messages is on the bus it will be dispatched to the appropriate message handler. You can then Publish from your handler. NSB will expose methods for each message handler that inherits the WcfService<T,K> class. Just keep using that class to expose more methods.
Related
I have given reference to a dll in my WCF service application. My WCF operation requires input of type class (let's say XYZ) which is present in that dll.
Now, is it possible to expose that class to the clients so that they can call the exposed wcf method?
If yes then can you please explain the idea or with some pesudo code/references ?
Thanks in advance !
Contract:
[OperationContract]
void Add(XYZ item);
Server:
public void Add(XYZ item){}
[DataContract]
class XYZ{}
Client:
var item = new XYZ();
client.Add(item);
Dll containing 'XYZ' should be referenced by both Server and Client.
Class 'XYZ' should have 'DataContract' attribute.
Implementation is more or less similar to FaultContracts in WCF.
We have already Business logic layer available in our application. It has lots of classes. and this is in separate library(.Dll). Now we want to use this in to our WCF Service. For that We create new project and gave reference to that .Dll. But we are not able to see our class .. I verify that class is public..
Could you please let me know what should I do?
Here I am attaching my code what I need to do
My Business Layer class
namespace BusinessLayer
{
public class MessageContext : Dictionary<string, object>
{ ....}
}
Now I am reference this Project to my WCF project and tried to expose this class into WCF client. So I Create one MessageContextHelper class which inherit from MessageContext the code is following
namespace WCFService
{
public class MessageContextHelper : MessageContext
{ ...... }
}
On client I am not able to get MessageContextHelper class.
Thanks
JK
WCF doesn't send business logic classes to the client. If you're using the SOAP version of WCF (BasicHttpBinding for example) then what WCF will expose is methods that are in your service contract. Your client can call those.
So if you have methods in a business logic class that you want exposed, create methods in your WCF service that will in turn call the business layer methods.
A very rudimentary (and not complete) version would look something like this:
namespace WCFService
{
public class MyService: IMyService
[OperationContract]
public String DoSomeStuff() {
return MessageContext.DoSomething();
}
}
You absolutely cannot (and should not) use your business layer from your client code. As the previous reply message, WCF does not send your business class to the client. Think about how long it will take to send. The business layer (your dll) should be used on the server only. Your WCF should only accept modified/new data from the client, pass the data to the business layer, and then return the results to the client.
I have a service (Service1) that uses another serice (Service2). I am using Dependency injection for both services and need to inject the proxy for Service2 into Service1.
I am unsure how to deal with the fact that the proxy is not a simple class of type IService2 but a proxy inheriting from ClientBase as well. Obviously my Service1 implementation needs to open the proxy and should also close it after use or abort it if an exception occurs but if I am just injecting an instance of IService2 then I cannot do this (without casting) because the Open, Close and Abort methods are on the base class whilst my operations are on the interface.
When it comes to testing Service1, I would expect to mock just the interface but if the Service1 implementation expect Open, Close and Abort methods, then this is tricky. In the past, I have done something hacky like this but there must be a better way!
var proxyBase = _service2 as ClientBase;
if (proxyBase != null)
{
proxyBase.Open();
}
_service2.DoOperation("blah"); //the actual operation
if (proxyBase != null)
{
proxyBase.Close();
}
// repeat for Abort in exception handler(s).
What are other people doing?
Thanks
The auto generated class that you get for adding a service reference for a WCF service is implemented as a partial class. What I do is create a another partial file for that class and implement an interface that exposed those methods, and then use that interface where you would normally use the ClientBase or WCF interface
public partial class Service2 : IClientService2
{}
If IClientService2 has the Abort and Close methods that match the ClientBase methods it should be all you need.
public interface IClientService2 : IService2 // where IService2 is the WCF service interface
{
void Abort();
void Close();
}
I suggest injecting a factory to construct WCF services rather than injecting the proxy itself since when a fault occurs then the channel is no longer able to be used and you will need to construct a new proxy.
IClientService2 proxy = _service2Factory.Create();
proxy.Open();
proxy.DoOperation("blah"); //the actual operation
proxy.Close();
Your interface is poluted because of the requirements imposed by Wcf. If you were not using wcf you would not have an Open and Close method. In an ideal world the interface should look the same as if the service was in process.
Have you chosen your IoC container yet? If you haven't I would consider looking at Windsor. This will allow you to maintain a clean interface and either inject the service as an in process object or a wcf proxy.
container = new WindsorContainer().AddFacility<WcfFacility>();
container.Register(Component
.For<IClientService2>()
.ActAs(DefaultClientModel)
.On(WcfEndpoint.FromConfiguration("YourServiceNameInConfiguration")))
.LifeStyle.Transient);
The WcfFacility will do all the opening and closing of the channel for you.
I ended up using this approach which uses Castle Dynamic Proxy to intercept calls and handle WCF specifics. It works really well and allows the class where the proxy is injected to treat it like a normal class / interface. This class is then totally unit testable by mocking the service contract interface.
I have a plugin that I will instantiate at runtime and I want to pass it a WCF service from the application host. The application host is responsible for creating the connection to the service. The reason for this is that a single service can be used by multiple plugins, but the plugins should only know about its interface since there may be several implementation of IMyPluginServices. For instance, the Run method of the plugin instance would be:
public void Run(IMyPluginServices services)
{
services.DoSomething();
}
The problem I am running into is that I don't know how to create a service of type IMyPluginServices and pass it to the Run function. The service reference generated by VS 2010 doesn't seem to create an object of type IMyPluginServices that I can pass to it. Any help would be greatly appreciated. Thanks.
When you add a service reference in VS 2010 for a service it generates an interface named IMyService which contains methods for each OperationContract in your service. It also generates a concrete class named MyServiceClient, which can be constructed and then used to invoke your service.
Now, the problem that you're running into, I believe, is that MyServiceClient is a subclass of ClientBase<IMyService>, and does not implement the generated IMyService interface (which is a real pain).
To get around this problem I ended up making a new interface:
public interface IMyServiceClient : IMyService, IDisposable, ICommunicationObject
{
}
(Note: IDisposable and ICommunicationObject are only required if you want your module to be able to detect/react to faulted channels and other such things).
I then extend MyServiceClient with a partial class (in the assembly that contains my WCF Service reference):
public partial class MyServiceClient : IMyServiceClient
{
}
Now in my modules I can accept an IMyServiceClient instead of an IMyService, and still execute all of the methods that I need to. The application in control of the modules can still create instances of MyServiceClient as it always did.
The beauty of this is that your new interface and partial class don't need any actual code - the definitions suffice to get the job done.
I have an service Interface:
[ServiceContract]
[ServiceKnownType(typeof(Models.ArticleImage))]
public interface IPhotoManagementService
{
[OperationContract]
bool Login(string username, string password);
[OperationContract]
bool IsLoggedIn();
[OperationContract]
void UpdateImage(string articleID, string selectedImage);
}
As you can see I specify a typeof(Models.ArticleImage) on my ServiceContract.
So building the WSDL of this service should cause ArticleImage to pop up in the WSDL. Unfortunarly this doesn't happen at all. Why is that?
ArticleImage has DataContract on it. And when I return an ArticleImage in my interface, then the WSDL does pick up ArticleImage.
Edit: it doesn't even pop up in the service reference in the consuming project!
This is the result of a lot of testing:
The model I'm trying to add is a LINQ to SQL model.
When I add a normal model with ServiceKnownType it works.
When I use my LINQ to SQL entities in my Interface it works.
When I add my LINQ to SQL entity through ServiceKnownType it doesn't pop up.
Only types used as input/output parameters of service contract operations are published in the WSDL.
Why would it need to? Where does your service expose something that could possibly be an ArticleImage?
Re your comment; when using [ServiceKnownType], the extra trype is still exposed in the "mex" (consumed via "svcutil") - but not by the WSDL. Are you using a WCF client? It should appear (I've just checked... it did). In general, though, returning vague data from a web-service isn't a great idea... sub-types, sure! Dictionary<string,ArticleImage> or even Dictionary<string,SomeBaseType> (with [KnownType] etc), fine! But object, HashTable, etc - aren't a good idea (IMO).
You might also just return a list of your type (List<ArticleImage>) which will work in all scenarios (and be easy for WSDL etc); and let the client make the dictionary at their end.
With regards to LINQ-to-SQL; objects for "mex" need to be decorated with [DataContract] / [DataMember]. You can do this in the designed by toggling the "serialization" property for the dbml. With this set (Serialization Mode = Unidirectional), it should work. To be honest, though, I think you be better-off just adding a dummy method that makes the type explicit on the API.