I have two different servers on which two similar WCF services are running. Both services are exactly same (clone). I have to consume both services in a single orchestration because I have to communicate them with each other. (I am using "Add generated Items" to add service reference). I want to get data from one service method named "Get" and send it to others "Send" method. After deploying project I get error that "Cannot locate document specification because multiple schemas matched the message type #####".
I have read a solution of creating custom pipeline with a specific document schema but that didn't worked.
How I can handle this situation?
If the services really are identical, then you don't need to use the wizard to import the schema twice - just import the first service's WSDL to create the schemas and port types, and then create a new send port* and change the bindings accordingly to point to the second service (i.e. notably the service URL).
This situation also typically happens if your WCF Services use MessageContracts which accepts or returns the same message payload for more than one service call (as opposed to DataContract, where you should get typically 'uniquified' root element names of the form xmlns#MyMethod and xmlns#MyMethodResponse).
In this case (i.e. common MessageContracts), in addition to basvo's answer, you can also get around this issue as follows:
Import all artifacts for all consumed WCF services into your BTS project in Visual Studio.
Retain the first 'instance' of each request (or response schema), and then in Orchestration view in VS, go through each of the second and subsequent port types and delete the duplicated request or response messages ("operation message") on the Port type. (Under each Port Type, you should see the request, the response and also any fault message types)
You then need to 'edit' each of the message types that you've deleted, and then manually go and change it to the original instance of the schema that you've retained.
You may also need to delete or worse, hack, the duplicated message types out of the imported .xsd files.
This is a pain however if your web service changes and you need to 'refresh' your imported schemas again - it would be a nice feature if the Import Wizard detected duplicate schemas and offered to merge them in this way for you.
*
Update - just to clarify, reuse the same logical send port in your orch design, but create a new Send Port in the deployed BTS server / cluster, subscribing the send port to the required messages / link the second Orch to the send port (depending on whether you are using Direct binding or not), and obviously change the binding to the second URL.
The problem is that you now have more than one schema in your BizTalk application which has the same namespace and root element.
You need to set the DocumentSpecNames property on both the XMLReceivePipeline of your "get service" and the XMLTransmitPipeline of your "send service" to tell BizTalk which one to use.
The basic format of this value is ... Schemaname+Rootname,Assembly
Example:
Company.Schemas.Messages+GetReply,Company.Schemas,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
As these services are same so just adding service reference for any one of these will add the required schemas.Just create separate send ports for each service in BizTalk MMC and to connect the logical port created in orchestration to correct send port while configuring the orchestration.
This solution Worked.....
Related
We are trying to build a Nservicebus service that can communicated with form and wpf based clients using WCF. I have read that you can inherit from WcfService.
like:
public class ThirdPartyWebSvc : WcfService<ThirdPartyCmd, ThirdPartyCmdResponse>
And then you simple create a endpoint in the app.config and you done like described here. but the problem is that i have to create a endpoint for every command.
I would like to have a single endpoint that excepts any command and returns its response.
public class ThirdPartyWebSvc : WcfService<ICommand, IMessage>
Can someone point me in the right direction? Using Nservicebus for client communication can't be done for us and i don't want to build a proxy like server unless thats the only way to do it.
Thanks
So from what I can gather, you want to expose a WCF service operation which consumers can call to polymorphically pass one of a number of possible commands to, and then have the service route that command to the correct NServiceBus endpoint which then handles the command.
Firstly, in order to achieve this you should forget about using the NserviceBus.WcfService base class, because to use this you must closely follow the guidance in the article you linked in your post.
Instead, you could:
design your service operation contract to accept polymorphic requests by using the ServiceKnownType attribute on your operation definition, adding all possible command types,
host the service using a regular System.ServiceModel.ServiceHost(), and then configure an NserviceBus.IBus in the startup of your hosted WCF service, and
define your UnicastBusConfig config section in your service config file by adding all the command types along with the recipient queue addresses
However, you now have the following drawbacks:
Because of the requirement to be able to pass in implementations of ICommand into the service, you will need to recompile your operation contract each time you need to add a new command type.
You will need to manage a large quantity of routing information in the config file, and if any of the recipient endpoints change, you will need to change your service config.
If your service has availability problems then no more messages to any of your NSB endpoints.
You will need to write code to handle what to do if you do not receive a response message from the NSB endpoints in a timely manner, and this logic may depend on the type of command sent.
I hope you are beginning to see how centralizing this functionality is not a great idea.
All the above problems would go away if you could get your clients to send commands to the bus in the standard way, but without msmq how can you do that?
Well, for a start you could look at using one of the other supported transports.
If none of these work for you and you have to use WCF hosted services, then you must follow the guidance in the linked article. This guidance is there to steer you in the correct direction - multiple WCF services sounds like a pain, until you try to centralize them into a single service - then the pain gets bigger, not less.
I have five separate services where each one corresponds to a different database table such as Product, User, Orders etc.
I am trying to send my custom exceptions across WCF. I have browsed the internet and i have wrapped my custom exceptions inside a fault exception:
interface
[FaultContract(typeof(NoSuchInstanceException))]
cs
throw new FaultException<NoSuchInstanceException>(e, new FaultReason(e.Message), newFaultCode("UserFault"));
The problem is when i update the service the client proxy disappears. I browsed the internet and found the following solution which says to add a mapping to the service reference SVCMAP file. http://travisspencer.com/blog/2007/11/
<NamespaceMapping
TargetNamespace="http://schemas.datacontract.org/2004/07/MyCompany.MyProject.Exceptions" ClrNamespace="MyCompany.MyProject.Exceptions" />
</NamespaceMappings>
My problem is that every service needs the custom exceptions adding to the mapping but when i do this. An error is displayed saying the exception is already defined in one of the other services. Do i merge the services into one service? Any help is really appreciated. Thanks
I can think of two options:
Merge the services into one - having multiple services sharing the same data types gives this problem on the client.
Move the shared data types into a separate dll (class library project). Then reference that shared data type library from both your server and client. When you create the services reference, choose the option to reuse data types.
I have a universal service hosted on IIS7 that accepts a Message and returns Message ( with Action="*"). This service still publishes meta for the clients.
This metadata is explicitly specified using LocationUrl property in ServiceMetadataBehavior.
We have a requirement that the metadata can change during lifetime of the service, so in essence metadata has a lifetime.
I tried adding IWsdlExportExtension to the service endpoint behavior, but the ExportEndpoint method only gets called once (when the service is loaded first time). Is there a way for me to invalidate the loaded metadata so that anytime there is a call for wsdl using HttpGet, the behavior gets called ?
What you are asking for (changing the published service definition at runtime) is not possible - you need to remove the requirement which specifies that the metadata can change over time.
Once you've published a service, the only reason the service specification should change is because the service has been upgraded.
You should look closer at the business requirement which is making this technical requirement necessary, and try to find another way to satisfy it (perhaps post in programmers.stackexchange). Perhaps you can have multiple services available, and switch between the services over time - but this is a bit of a stab in the dark without knowing the business requirement.
No there is no way. Moreover if you needed you are up to your fully custom solution because this is out of scope of web services. Changing metadata means changing the service itself = its internal logic which always result in restarting the hosting process and publishing new metadata.
I've got some WCF services (hosted in IIS 6) which use the Enterprise Library (4.0) Validation Application Block. If a client submits a message which fails validation (i.e. gets thrown back in a ValidationFault exception), I'd quite like to be able to log the message XML somewhere (using code, no IIS logs). All the validation happens before the service implementation code kicks in.
I'm sure it's possible to set up some class to get run before the service implementation (presumably this is how the Validation Application Block works), but I can't remember how, or work out exactly what to search for.
Is it possible to create a class and associated configuration that will give me access to either the whole SOAP request message, or at least the message body?
Take a look at using the Policy Injection Application Block...
I'm currently developing an application in which I intercept (using PIAB) all requests incoming to the server and based on the type of request I apply different validation behavior using the VAB.
Here's an article about integrating PIAB with WCF:
http://msdn.microsoft.com/en-us/magazine/cc136759.aspx
You can create different inteception mechanisms such as attributes applied to exposed operations.
You could log the whole WCF Message:
http://msdn.microsoft.com/en-us/library/ms730064.aspx
Or you could combine it with Enterprise Library Logging Application Block.
I found a blog post which seems to do what I want - you create a class that implements IDispatchMessageInspector. In the AfterReceiveRequest method, you have access to the whole incoming message, so can log away. This occurs after authentication, so you also have access to the user name - handy for logging. You can create supporting classes that let you assign this behaviour to services via attributes and/or configuration.
IDispatchMessageInspector also gives you a BeforeSendReply method, so you could log (or alter) your response message.
Now when customers attempt to literally hand-craft SOAP request messages (not even using some kind of DOM object) to our services, we have easy-to-access proof that they are sending rubbish!
I'm creating a WCF service that may be used either locally or remotely, and processes files sometimes using third-party components applications that unfortunately require as input a path to actual file on the filesystem, not a .net Stream or anything like that. Is there a standard approach for this situation, in terms of what the parameters to contract operations should be etc.? Although I suppose this can't be vital since it ultimately has to perform acceptably in both the local and remote cases, I'd prefer if, in the local case, it didn't have to read the whole file from the filesystem, include the contents in the message, and rematerialize it again on the filesystem, but for remote use this is necessary. Is there a way to do this e.g. by having an FSRefDoc type which serializes differently depending on whether it's used locally or remotely?
edit: To clarify: The problem is that I want to send different pieces of information entirely in the two cases. If I'm controlling a local service, I can just send a path to the file on the local filesystem, but if it's a remote service, I have to send the file contents themselves. Of course I can send the contents in both cases, but that means I lose performance in the local case. Maybe I shouldn't be worried about this.
OK,
Following your update, I would consider the following.
1) Create a method that takes a path. Expose this via a named pipe binding and use this locally.
2) Create a method that takes a file (stream/byte array etc). Expose this using an appropriate binding (on a different end point) for non local computers (in a LAN scenario TCP is usually your best bet).
Then all you need to do is make sure you don't duplicate the same business logic. So in a nutshell- create 2 different service interfaces, 2 different end points and 2 different bindings.
Well, you really touch on two separate issues:
local vs. remote service availability
"normal" vs. streamed service (for large files)
In general, if your service works behind a corporate firewall on a LAN, you should use the NetTcpBinding since it's the fastest and most efficient. It's fast and efficient because it uses binary message encoding (vs. text message encoding over the internet).
If you must provide a service for the "outside" world, you should try to use a binding that's as interoperable as possible, and here your choices are basicHttpBinding (totally interoperable - "old" SOAP 1.1 protocols) which cannot be secured too much, and wsHttpBinding which offers a lot more flexibility and options, but is less widely supported.
Since you can easily create a single service with three endpoints, you can really create your service and then define these three endpoints: one for local clients using NetTcpBinding, one of the widest availability using basicHttpBinding, and optionally another one with wsHttpBinding.
That's one side of the story.
The other is: for your "normal" service calls, exchanging a few items of information (up to a few KB in size), you should use the normal default behavior of "buffered transfer" - the message is prepared completely in a buffer and sent as a whole.
However, for handling large files, you're better off using a streaming transfer mode - either "StreamedResponse" if you want clients to be able to download files from your server, or "StreamedRequest" if you want clients to be able to uplaod files, or just plain "Streamed" if you send files both ways.
So besides the three "regular" endpoints, you should have at least another endpoint for each binding that handles streaming exchange of data, i.e. upload/download of files.
This may seems like a lot of different endpoints - but that's really not a problem, your clients can connect to whatever endpoint(s) are appropriate for them - regular vs. streamed and internal/local (netTcpBinding) vs. external (basicHttpBinding) as they need - and in the end, you write the code only once!
Ah , the beauty of WCF! :-)
Marc
UPDATE:
OK, after your comment, this is what I would do:
create a ILocalService service contract with a single method GetFile that returns a path and file name
create an implementation for the service contract
host that service on an endpoint with netTcpBinding (since it's internal, local)
[ServiceContract]
interface ILocalService
{
[OperationContract]
string GetFile(......(whatever parameters you need here).....);
}
class LocalService : ILocalService
{
string GetFile(......(whatever parameters you need here).....)
{
// do stuff.....
return fileName;
}
}
and secondly:
create a second service contract IRemoteService with a single method GetFile which doesn't return a file name as string, but instead returns a stream
create an implementation for the service contract
host that service on an endpoint with basicHttpBinding for internet use
make sure to have transferMode="StreamedResponse" in your binding configuration, to enable streaming back the file
[ServiceContract]
interface IRemoteService
{
[OperationContract]
Stream GetFile(......(whatever parameters you need here).....);
}
class RemoteService : IRemoteService
{
Stream GetFile(......(whatever parameters you need here).....)
{
// do stuff.....
FileStream stream = new FileStream(....);
return stream;
}
}