I came across a page on MSDN explaining transaction in WCF Services here. I tweaked the binding settings and used netTcpBinding. Here is the serviceModel section of my app.config file:
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="netTcpBindingConfiguration1" transactionFlow="true">
<security mode="Message" />
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="OrderingService.OrderService">
<clear />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"
listenUriMode="Explicit">
</endpoint>
<endpoint address="net.tcp://localhost:8880/OrderingService"
binding="netTcpBinding" bindingConfiguration="netTcpBindingConfiguration1"
contract="OrderingService.IOrderService" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8888/OrderingService/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" />
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
I created a windows application as the client of the service. I used netstat command to see the TCP connections between the client and the service (hosted in a console application). I realized for each operation (which was a button click in my client app that places a new order by invoking the methods of the service's proxy class), a new connection is created and all previous connections still remain ESTABLISHED. Obviously, this is not an ideal condition. I wondered what I did wrong and what setting or configuration would work out this problem by reducing the number of connections to only one. By the way, the service class that implements the service interface has InstanceContextMode set to PerSession. Here are the contract interface and the service class:
[ServiceContract(SessionMode=SessionMode.Required)]
public interface IOrderService
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.NotAllowed)]
List<Customer> GetCustomers();
[OperationContract]
[TransactionFlow(TransactionFlowOption.NotAllowed)]
List<Product> GetProducts();
[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
string PlaceOrder(Order order);
[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
string AdjustInventory(int productId, int quantity);
[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
string AdjustBalance(int customerId, decimal amount);
}
[ServiceBehavior(TransactionIsolationLevel = IsolationLevel.Serializable,
TransactionTimeout = "00:00:20",
InstanceContextMode = InstanceContextMode.PerSession,
TransactionAutoCompleteOnSessionClose = true)]
public class OrderService : IOrderService
{...}
Here is the code the uses the proxy class in the client app:
using (TransactionScope scope = new TransactionScope())
{
try
{
proxy = new OrderServiceClient("NetTcpBinding_IOrderService");
result = proxy.PlaceOrder(order);
MessageBox.Show(result);
result = proxy.AdjustInventory(product.ProductId, quantity);
MessageBox.Show(result);
result = proxy.AdjustBalance(customer.CustomerId, product.Price * quantity);
MessageBox.Show(result);
proxy.Close();
scope.Complete();
}
catch (Exception exc)
{
MessageBox.Show("Error occurred: " + exc.Message);
}
}
With regards to the TCP connection remaining ESTABLISHED - are you calling .Close() on your instance of the client when you are finished with it?
If you want to use a single connection you should change the instance context mode to 'Single' and reuse the connection you establish in the client to process all your service calls. This suits an architecture where you want to maintain state within your service.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class Service : IService
{
}
I found this link very helpful when I was learning about context modes in WCF: CodeProject link
As you are currently using PerSession context mode you should be able to limit it to a single connection by adding a setting for maxConcurrentSessions in your behaviors section. You can do it like this:
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" />
<serviceDebug includeExceptionDetailInFaults="False" />
<serviceThrottling maxConcurrentSessions="1" />
</behavior>
</serviceBehaviors>
This would only be a good idea if you have a single client.
I have two classes implementing a contract at a service which are consumed from a factory on the client like shown below.
[ServiceContract]
public interface MyInterface {
void DoSomething()
}
public class A : MyInterface {
public void DoSomething(){
"Hi I'm A"
}
}
public class B : MyInterface {
public void DoSomething(){
"Hi I'm B"
}
}
public class MyFactory <TMyInterface> {
void DoSomething(){
TMyInterface.DoSomething()
}
}
The client must remain the same. My question is how can I choose at the server side which implementation of MyInterface to use, by passing the type parameter using .config file in WCF
I read other post but I don't understand yet :(
It is possible to do it, and there are a few ways to do it.
One possibility is to create a "routing" service which will contain the "public" address which the client always talks to. This routing service can then, based on some configuration, redirect the call to the appropriate "real" service.
Another way is to actually have a process which starts both services, but their addresses are defined in config. If you use the same binding and the same contract (which is the case), then you can "flip-flop" the service address when you want to change the service which will receive the calls from the client. For example, this configuration directs the requests to the endpoint at "http://machine-name:8000/Service" to service A. Notice that, since you define service hosts for both services, you actually need to have a base address for service B as well - in this case I used named pipes, which cannot be accessed via different machines.
<system.serviceModel>
<services>
<service name="A">
<host>
<baseAddresses>
<add baseAddress="http://machine-name:8000/Service"/>
</baseAddresses>
</host>
<endpoint address="" binding="basicHttpBinding" contract="MyInterface" />
</service>
<service name="B">
<host>
<baseAddresses>
<add baseAddress="net.pipe://localhost/ServiceBackup"/>
</baseAddresses>
</host>
<endpoint address="" binding="netNamedPipeBinding" contract="MyInterface" />
</service>
</services>
</system.serviceModel>
when you want to change the address for B, you'd then swap the addresses.
<system.serviceModel>
<services>
<service name="A">
<host>
<baseAddresses>
<add baseAddress="net.pipe://localhost/ServiceBackup"/>
</baseAddresses>
</host>
<endpoint address="" binding="netNamedPipeBinding" contract="MyInterface" />
</service>
<service name="B">
<host>
<baseAddresses>
<add baseAddress="http://machine-name:8000/Service"/>
</baseAddresses>
</host>
<endpoint address="" binding="basicHttpBinding" contract="MyInterface" />
</service>
</services>
</system.serviceModel>
The hosting program would look like this:
public static void HostServices()
{
ServiceHost hostA = new ServiceHost(typeof(A));
ServiceHost hostB = new ServiceHost(typeof(B));
hostA.Open();
hostB.Open();
Console.WriteLine("Press ENTER to close");
Console.ReadLine();
hostA.Close();
hostB.Close();
}
Now, if your services are hosted in IIS (webhost), then it's a little harder. Since the "normal" activation requires a .svc file to be part of the endpoint address, and each .svc file is associated with a single class, the address for A would be something like http://machine-name/services/a.svc while the address for B would be something like http://machine-name/services/b.svc. So what you'd need to do in this case is to create a custom ServiceHostFactory, and use the ASP.NET Routes integration to create a .svc-less URL for your service. Then you'd use something similar to the previous example to decide which service will be activated.
I wrote some service that have method that get image ( byte[] ) as parameter ( return void ).
I also wrote some client (client & server run on same machien - different sulotion - using IIS )that send the bitmap ( as byte[] ) to the service - and each time i try to send i get the exception:
An error occurred while receiving the HTTP response to http://localhost/WebService/Service.svc. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down)
I added one more method that get void and return int - and i can call this method with no problem.
What can be wrong ? Do i need to define something speciel in the client service reference ?
The service method
[ServiceContract]
**public interface IService**
{
[OperationContract]
void GetPic( byte[] pic );
}
**public class Service : IService**
{
public void GetPic( byte[] pic )
{
...
}
}
Web.config file:
<system.serviceModel>
<services>
<service behaviorConfiguration="ServiceBehavior" name="ServiceProxy.Service">
<endpoint
name="basicHttp"
address=""
binding="basicHttpBinding"
bindingConfiguration=""
contract="Contracts.IService">
</endpoint>
<endpoint
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" >
</endpoint>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8731/ServiceProxy/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
You must configure your binding on server to accept large messages. By default it accepts only messages up to 65KB and arrays with 16k elements = in your case bitmap which has size less then 16KB.
Use this in your web.config (server side):
<bindings>
<basicHttpBinding>
<binding name="myBinding" maxReceivedMessageSize="1000000">
<readerQuotas maxArrayLength="1000000" />
</binding>
</basicHttpBinding>
</bindings>
In your endpoint configuration reference this binding in bindingConfiguration attribute by setting it to myBinding.
I've spent a couple of hours searching about this error, and I have tested almost everything it's on Google.
I want to access a service using TCP, .NET4 and VS2010, in C#.
I Have a very tiny service:
namespace WcfService_using_callbacks_via_tcp
{
[ServiceContract(CallbackContract = typeof(ICallback), SessionMode = SessionMode.Required)]
public interface IService1
{
[OperationContract]
string Test(int value);
}
public interface ICallback
{
[OperationContract(IsOneWay = true)]
void ServerToClient(string sms);
}
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service1 : IService1
{
public string Test(int value)
{
ICallback the_callback = OperationContext.Current.GetCallbackChannel<ICallback>();
the_callback.ServerToClient("Callback from server, waiting 1s to return value.");
Thread.Sleep(1000);
return string.Format("You entered: {0}", value);
}
}
}
With this Web.config:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="WcfService_using_callbacks_via_tcp.Service1" behaviorConfiguration="Behaviour_Service1">
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:5050/Service1" />
</baseAddresses>
</host>
<endpoint address="" binding="netTcpBinding" bindingConfiguration="DuplexNetTcpBinding_IService1" contract="WcfService_using_callbacks_via_tcp.IService1"/>
<endpoint address="mex" binding="mexTcpBinding" bindingConfiguration="mexTcp" contract="IMetadataExchange"/>
</service>
</services>
<bindings>
<!--
TCP Binding
-->
<netTcpBinding>
<binding name="DuplexNetTcpBinding_IService1" sendTimeout="00:00:01"
portSharingEnabled="true">
</binding>
<binding name="mexTcp" portSharingEnabled="true">
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<!--
Behaviour to avoid a rush of clients and to expose metadata over tcp
-->
<behavior name="Behaviour_Service1">
<serviceThrottling maxConcurrentSessions="10000"/>
<serviceMetadata httpGetEnabled="true"/>
</behavior>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
And this code to host it:
static void Main(string[] args)
{
Uri base_address = new Uri("net.tcp://localhost:5050/Service1");
ServiceHost host = null;
try
{
// Create the server
host = new ServiceHost(typeof(Service1), base_address);
// Start the server
host.Open();
// Notify it
Console.WriteLine("The service is ready at {0}", base_address);
// Allow close the server
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
// Close it
host.Close();
}
catch (Exception ex)
{
// Opus an error occurred
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(string.Format("Host error:\r\n{0}:\r\n{1}", ex.GetType(), ex.Message));
Console.ReadLine();
}finally
{
// Correct memory clean
if(host != null)
((IDisposable)host).Dispose();
}
}
Now I want to create the client, but I it is not posible. I've used Add Service Reference and svcutil directly, but I am receiving this error:
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC>svcutil.exe
net.tcp://loc alhost:5050/Service1 Microsoft (R) Service Model
Metadata Tool [Microsoft (R) Windows (R) Communication Foundation,
Version 4.0.30319.1] Copyright (c) Microsoft Corporation. All rights
reserved.
Attempting to download metadata from
'net.tcp://localhost:5050/Service1' using W S-Metadata Exchange. This
URL does not support DISCO. Microsoft (R) Service Model Metadata Tool
[Microsoft (R) Windows (R) Communication Foundation, Version
4.0.30319.1] Copyright (c) Microsoft Corporation. All rights reserved.
Error: Cannot obtain Metadata from net.tcp://localhost:5050/Service1
If this is a Windows (R) Communication Foundation service to which you
have acce ss, please check that you have enabled metadata publishing
at the specified addr ess. For help enabling metadata publishing,
please refer to the MSDN documentat ion at
http://go.microsoft.com/fwlink/?LinkId=65455.
WS-Metadata Exchange Error
URI: net.tcp://localhost:5050/Service1
Metadata contains a reference that cannot be resolved: 'net.tcp://localhost: 5050/Service1'.
The socket connection was aborted. This could be caused by an error processi ng your message or a receive timeout being exceeded by
the remote host, or an un derlying network resource issue. Local
socket timeout was '00:04:59.9863281'.
Se ha forzado la interrupción de una conexión existente por el host remoto
If you would like more help, type "svcutil /?"
So, I can host the service without problems but I can not create the proxies.
I've tried almost any config I've found, but I think the current web.config is correct. There are the behaviours, the security, and the bindings using mex, used by the endpoints.
I've tried to create an app.config and set it to the same folder with svcutil.exe.
You are missing service configuration
<system.serviceModel>
<services>
<service name="WcfService_using_callbacks_via_tcp.Service1"
behaviorConfiguration="Behavior_Service1">
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:5050/Service1" />
</baseAddresses>
</host>
<endpoint address="" contract="WcfService_using_callbacks_via_tcp.IService1"
binding="netTcpBinding" bindingConfiguration="DuplexNetTcpBinding_IService1" />
<endpoint address="mex" contract="IMetadataExchange" binding="mexTcpBindng" />
</service>
</services>
...
</system.serviceModel>
With this config you should not need to define base address in code.
I received the same error while attempting to update an existing service reference. It turns out I had data contracts with the same name within the same namespace. Further investigation yielded the real error:
DataContract for type [redacted] cannot be added to DataContractSet since type '[redacted]' with the same data contract name 'DocumentInfo' in namespace '[redacted]' is already present and the contracts are not equivalent.
I changed the DataContract to provide a name for one of the classes.
[DataContract(Namespace = "urn:*[redacted]*:DataContracts", Name = "SC_DocumentInfo")]
I'm posting this here in case it might help someone with the same issue.
I was getting the same error message and as it turned out, the issue was due to text within a comments block
<!-- comments included characters like à, ç and ã -->
After removing such characters from the commented block, everything works fine
Maybe it will be helpful for someone.
My issue was in a contract argument, and I discovered it with help of Event Viewer:
The operation [Name of method] either has a parameter or a return type that is attributed with MessageContractAttribute. In order to represent the request message using a Message Contract, the operation must have a single parameter attributed with MessageContractAttribute. In order to represent the response message using a Message Contract, the operation's return value must be a type that is attributed with MessageContractAttribute and the operation may not have any out or ref parameters.
So, if you appended more than one arguments, already having [MessageContract] argument, then you'll see error in question. Completely not obvious.
I had the same problem (when client didn't "see" the service in "Add service reference" menu) while using only tcp binding. After trying to add Behavior I had my service to end with exception because it didn't find proper address.
I don't know if it is the best idea, but you can add second base address as http.... here is my config and code, it works.
<?xml version="1.0" encoding="utf-8" ?><configuration> <system.serviceModel> <services>
<service name="TestBindings.StockQuoteService">
<host>
<baseAddresses>
<add baseAddress="net.tcp://10.62.60.62:34000/StockQuoteService" />
<add baseAddress ="http://10.62.60.62:12000/StockQuoteService"/>
</baseAddresses>
</host>
<endpoint address=""
contract="TestBindings.IStockQuoteService"
binding="netTcpBinding" />
</service>
</services>
And the code
class Program
{
static void Main(string[] args)
{
ServiceHost sh = new ServiceHost(typeof(StockQuoteService));
ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
behavior.HttpGetEnabled = true;
sh.Description.Behaviors.Add(behavior);
sh.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(),
"mex");
sh.Open();
The http address is now usend by client to add service reference, and automatically generated config on client side uses net.tcp protocol to call the function.
There is yet another reason to run into this one. Similar to the DataContract related answer here, WCF services also don't support method overloading in operation contracts. It'll raise this confusing catch-all exception as well.
The fix is simple enough:
[OperationContract]
T[] Query(int id);
[OperationContract(Name = "QueryWithArg")]
T[] Query(int id, string arg);
For the above issue check the reference.svc file which is generated at the time you add the reference. The url mentioned in that will be used for updating the service so you can check whether that is running or not.
I have a WCF service that is hosted in IIS. I want to use my own IAuthorizationPolicy, and have it configured in the web.config file on the server. I have my auth policy:
namespace MyLib.WCF
{
public class CustomAuthorizationPolicy : IAuthorizationPolicy
{
public CustomAuthorizationPolicy()
{
this.Id = Guid.NewGuid().ToString();
}
public bool Evaluate(EvaluationContext evaluationContext, ref object state)
{
throw new ApplicationException("Testing custom auth");
}
...
}
}
And in my web.config:
<service behaviorConfiguration="Behavior" name="MyService">
<endpoint address="" binding="wsHttpBinding" contract="IMyService"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
<serviceBehaviors>
<behavior name="Behavior">
<serviceAuthorization principalPermissionMode="Custom">
<authorizationPolicies>
<add policyType="MyLib.WCF.CustomAuthorizationPolicy, MyLib.WCF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</authorizationPolicies>
</serviceAuthorization>
</behavior>
</serviceBehaviors>
But my CustomAuthorizationPolicy.Evaluate() method never fires. What am I missing?
Well, the obvious (silly) question is: in your <service>, do you actually reference your behavior configuration??
I.e. do you have:
<system.serviceModel>
....
<service name="YourService" behaviorConfiguration="Behavior">
....
</service>
....
</system.serviceModel>
Just defining all your stuff is nice and well - but unless you've actually referenced it, it won't do you any good (been there, done that myself, too! :-) )
Second (almost as silly) question would be: what binding and security config do you use?? Have you even turned on security at all? If you have <security mode="None">, then your service authorization will obviously never be used, either (since no credentials are being passed to the service at all).
Marc