I am adding objects sent from a client to a list which is at the service, my issue is this, during debugging I see that as soon as i return from the main service to the client the list turns to 0. It's like the list gets emptied and as soon as the flow of the program returns to the client and then when the client sends data to the service the data are there, as soon as i enter the method of the service the list gets filled with the old data. I would like to access these data from another part of the program but i always see the list empty. Any tips?
As per my comment you need to setup the ServiceContract's SessionMode and also the ServiceBehavior's InstanceContextMode. The default InstanceContextMode is PerCall which means that your list will not be preserved. You need to change it to use PerSession. See below for fully working example (.NET 4):
Service Side Code:
using System.Collections.Generic;
using System.ServiceModel;
namespace WcfService1
{
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IService1
{
[OperationContract]
int AddData(string data);
[OperationContract]
List<string> GetData();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class Service1 : IService1
{
private readonly List<string> _myList = new List<string>();
public int AddData(string data)
{
_myList.Add(data);
return _myList.Count;
}
public List<string> GetData()
{
return _myList;
}
}
}
Service Side web.config
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<protocolMapping>
<add scheme="http" binding="wsHttpBinding"/>
</protocolMapping>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
Client Side:
using System;
using System.Collections.Generic;
using ConsoleApplication1.ServiceReference1;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main()
{
using (var service = new Service1Client())
{
// Add items...
int itemCount;
itemCount = service.AddData("Test Item 1");
Console.WriteLine("Service now holds {0} items", itemCount);
itemCount = service.AddData("Test Item 2");
Console.WriteLine("Service now holds {0} items", itemCount);
itemCount = service.AddData("Test Item 3");
Console.WriteLine("Service now holds {0} items", itemCount);
// Get all of the items added...
List<string> listFromService = service.GetData();
foreach (var listItem in listFromService)
{
Console.WriteLine(" * {0}", listItem);
}
Console.WriteLine();
}
Console.ReadKey();
}
}
}
Client Side app.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService1" />
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:59604/Service1.svc" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IService1" contract="ServiceReference1.IService1"
name="WSHttpBinding_IService1">
</endpoint>
</client>
</system.serviceModel>
</configuration>
Note: I had to ensure that wsHttpBinding was used as basicHttpBinding does NOT support sessions.
Related
I am writing a part of the program, which is used for communication between client and server.
Service only forwards the query to the database. But when I try to send a query I get an exception "ProtocolException / (405) Method not allowed".
I tried answers from ProtocolException Unhandled/(405) Method not allowed with WCF; Bindings and Endpoints look right though, but nothing helped.
Here are some of my files:
Client for communication It is library, because we want to use it from Unity and I also want this code in tests.
namespace Client
{
public class ClientCommunicationWcf : IDisposable
{
private readonly ChannelFactory<ITask> _taskFactory;
public ClientCommunicationWcf()
{
_taskFactory = new ChannelFactory<ITask>("localhost");
}
public T GetResponse<T>(string commandName, object data)
{
var channel = _taskFactory.CreateChannel();
channel.Execute(commandName, data);
return (T)channel.ResponseObject;
}
public void Dispose()
{
_taskFactory.Close();
((IDisposable) _taskFactory).Dispose();
}
}
}
DataContract
namespace CommunicationCommonLib.Requests
{
[DataContract]
[KnownType(typeof(LoginUserRequest))]
public class LoginUserRequest
{
[DataMember]
private readonly string _username;
[DataMember]
private readonly string _password;
public LoginUserRequest(string username, string password)
{
_username = username;
_password = password;
}
public string Username
{
get { return _username; }
}
public string Password
{
get { return _password; }
}
}
}
ServiceContract
namespace CommunicationCommonLib
{
[ServiceContract]
public interface ITask
{
object ResponseObject
{
[OperationContract]
get;
}
/// <param name="data"></param>
[OperationContract]
void Execute(string commandName, object data);
}
}
Service:
IServerTask is child of ITask
namespace WcfService2
{
public class ServerTaskService : IServerTask, ITask
{
private object _responseObject;
public object ResponseObject
{
get { return _responseObject; }
}
public void Execute(string commandName, object data)
{
DataCommands.RunCommand(commandName, data, this);
}
public void SetResponse(object response)
{
_responseObject = response;
}
}
}
Web.config
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="WcfService2.ServerTaskServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="WcfService2.ServerTaskServiceBehavior" name="WcfService2.ServerTaskService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding" contract="CommunicationCommonLib.ITask" />
</service>
</services>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="01:00:00" sendTimeout="04:00:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="209715200" maxBufferSize="52428800" maxReceivedMessageSize="52428800"
textEncoding="utf-8" transferMode="Streamed" useDefaultWebProxy="false"
messageEncoding="Mtom">
<readerQuotas maxStringContentLength="10485760" maxArrayLength="52428800" />
<security mode="None">
<transport clientCredentialType="None" />
</security>
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<client>
<endpoint address="http://localhost:55555/Task" binding="basicHttpBinding" contract="CommunicationCommonLib.ITask" name="localhost"/>
</client>
</system.serviceModel>
</configuration>
Address "http://localhost:5555/Task" is also set in WcfService2 - Properties - Web, where it is used IIS Express.
I wrote WPF application for testing client server communication, where is stored App.config. WPF is only for sending request and checking the result.
Web.config may be wrong, because it is my first WCF and I tried different things from examples.
When I run program, browser open "http://localhost:5555/Task", so I think that service is running.
Thanks for help.
EDIT: ServerTaskService is child of IServerTask and ITask.
Your service contract name is ITask while your service class implements some different interface i.e. IServerTask. Please correct service class definition.
Hey fellow developers and software-engineers,
I've recently run into a problem which doesn't let me access my WCF Services with a 404 (using ChannelFactory).
Here are the details:
multiple Webservers hosting the same WS (WCF.Net4/IIS8.5)
Server web.config of each WS:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
<customErrors mode="Off"/>
</system.web>
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="crossDomain" crossDomainScriptAccessEnabled="true"/>
</webHttpBinding>
<basicHttpBinding>
<binding name="" maxReceivedMessageSize="26144"/>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="enableScriptBehaviour">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="IISManagerWS.WS">
<endpoint address="" binding="webHttpBinding" behaviorConfiguration="enableScriptBehaviour" contract="ContractDll.IWS"/>
</service>
</services>
<serviceHostingEnvironment multipleSiteBindingsEnabled="True" />
</system.serviceModel>
</configuration>
Important Note for the WS: I've used a ClassLibrary for the Service Contract so I could work with the ChannelFactory in the client.
Why I am using a ChannelFactory? It simply seemed the easiest way to consume multiple WS which are all the same. Because the number
of these Webservices can become more I'd wanted it to be dynamically via code.
Interface of the Contract Dll:
namespace ContractDll
{
[ServiceContract]
public interface IWS
{
[WebGet()]
[OperationContract]
WebSite[] getLocalSiteInventory();
}
[DataContract]
public class WebSite
{
[DataMember]
public String Name { get; set; }
[DataMember]
public String AppPool { get; set; }
[DataMember]
public String Authentication { get; set; }
[DataMember]
public String Path { get; set; }
[DataMember]
public String Server { get; set; }
[DataMember]
public Boolean HasSSL { get; set; }
}
}
On the Client Side I've got an empty app.config except for the connectionstring, so nothing special here.
The whole lot of magic should happen in the code behind:
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress address = new EndpointAddress(ServiceURL);
ChannelFactory<IWS> factory = new ChannelFactory<IWS>(binding, address);
IWS channel = factory.CreateChannel(address);
WebSite[] sites = channel.getLocalSiteInventory();
But just when the call of my WS-Method gets going I happen to get an exception:
There was no endpoint listening at 'http://dev-02.apps.rd.local/IISManagerWS/ws.svc' that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.
And the inner Exception goes:
(404) Not found.
If I access the WS via URL:
I've tried alot of research but even if there are lot of topics that look the same I had no success in solving this error.
Found the Solution myself while reading about designing RESTful Webservices.
WebChannelFactory<IWS> cf = new WebChannelFactory<IWS>(new Uri(ServiceURL));
IWS channel = cf.CreateChannel();
WebSite[] sites = channel.getLocalSiteInventory();
I am newbie in creating WCF web service. I am using VS2012 with target framework 4.5. I have added a WCF Service file in my project.
In "IService.cs" I have written the following code
namespace _3TWebServ
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped,
RequestFormat = WebMessageFormat.Json,
UriTemplate = "Calculate")]
String Calculate(Inputs ip1);
}
[DataContract]
public class Inputs
{
[DataMember(Name = "Coil_type")]
public string Coil_type { get; set;}
[DataMember(Name = "Finned_length")]
public string Finned_length { get; set;}
}
}
and in "Service.svc.cs"
namespace _3TWebServ
{
public class Service1 : IService1
{
[DataMember]
public string input;
public String Calculate(Inputs ip1)
{
String str = ip1.Coil_type + ip1.Finned_length;
return str;
}
}
}
But the problem comes when I run my service its not showing my method Calulate, When I pass my URL as Following
localhost:2121/Service1.svc/Calculate it shows "method not allowed" error.
I have done some Googling and enabled my IIS manager Directory Browsing. My config file is following
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" />
</system.web>
<system.serviceModel>
<services>
<service behaviorConfiguration="_3TWebServ.IService1" name="_3TWebServ.Service1">
<endpoint address="" behaviorConfiguration="Rest" binding="webHttpBinding" contract="_3TWebServ.IService1">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<!--endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />-->
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="_3TWebServ.IService1">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="Rest">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
I can see a few possible issues.
Your Calculate method is set for a HTTP POST request. You should make a HTTP POST request to get proper response.
Your request format is JSON (RequestFormat attribute property value), so make sure your request body contains the parameters in JSON format ({ "Coil_type" : "type", "Finned_length": 12 }).
Why do you have the [DataMember] public string input on the service implementation? Service implementations should generally carry operation contracts.
I seem to be having a problem for getting IErrorHandler interface to work. My code is
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
namespace WcfService3
{
public class Service1 : IService1
{
public string GetData(int value)
{
throw new Exception("asdf");
}
}
public class MyErrorHandler : IErrorHandler
{
public MyErrorHandler()
{
string Hello = "";
}
public bool HandleError(Exception error)
{
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message msg)
{
var vfc = new MyFault();
var fe = new FaultException<MyFault>(vfc);
var fault = fe.CreateMessageFault();
msg = Message.CreateMessage(version, fault, "http://ns");
}
}
public class ErrorHandlerExtension : BehaviorExtensionElement, IServiceBehavior
{
public override Type BehaviorType
{
get { return GetType(); }
}
protected override object CreateBehavior()
{
return this;
}
private IErrorHandler GetInstance()
{
return new MyErrorHandler();
}
void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
IErrorHandler errorHandlerInstance = GetInstance();
foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
{
dispatcher.ErrorHandlers.Add(errorHandlerInstance);
}
}
void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ServiceEndpoint endpoint in serviceDescription.Endpoints)
{
if (endpoint.Contract.Name.Equals("IMetadataExchange") &&
endpoint.Contract.Namespace.Equals("http://schemas.microsoft.com/2006/04/mex"))
continue;
foreach (OperationDescription description in endpoint.Contract.Operations)
{
if (description.Faults.Count == 0)
{
throw new InvalidOperationException("FaultContractAttribute not found on this method");
}
}
}
}
}
}
My web.config is:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<services>
<service name="WcfService3.Service1">
<endpoint address=""
binding="basicHttpBinding"
contract="WcfService3.IService1" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="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>
<extensions>
<behaviorExtensions>
<add name="errorHandler"
type="WcfService3.ErrorHandlerExtension, WcfService3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>
</extensions>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
My WCF interface is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace WcfService3
{
[ServiceContract]
public interface IService1
{
[OperationContract]
[FaultContract(typeof(MyFault))]
string GetData(int value);
}
[DataContract]
public class MyFault
{
}
}
My question is in IErrorHandler in WCF, if there is any exception during the WCF service call, the HandlerError() function is suppose to get called first like the C# windows application UnhandledException class and then the service should crash right? In the code above, during the service call, an exception is thrown but my HandlerError function is not getting called before the exception is thrown? My goal is to log the error and the WCF service can throw the unhandled exception and crash. I was expecting during the debugging that the breakpoint will visit the HandleError function, but that function is not getting called and just an exception shows up?
Aren't you missing <errorHandler /> in your behavior section?
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<!-- HERE -->
<errorHandler />
<!-- HERE -->
</behavior>
The full answer is here. Plus 1 to that answer.
In case anyone else comes across this, when I ran across this error, it was because the error was getting thrown in a method that was called from some LINQ expression. The method wasn't actually called until WCF tried to serialize the response, which then threw outside of the service scope. WCF won't pass these errors to the IErrorHandler.
Materializing the list before returning using .ToList() solved this problem for me.
I was new to WCF, i was trying to build a sample application using VS 2010 and code provided below
IProductService.cs
[ServiceContract]
public interface IProductService
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Xml)]
Products SelectAllProducts();
}
[DataContract]
public class Product
{
[DataMember]
public int ProductId { get; set; }
[DataMember]
public string Name { get; set; }
}
[CollectionDataContract]
public class Products : System.Collections.ObjectModel.Collection<Product>
{
}
ProductService.cs
public class ProductService : IProductService
{
public Products SelectAllProducts()
{
var products = new Products();
var prod = new Product();
prod.ProductId = 1;
prod.Name = "SAMSUNG";
products.Add(prod);
prod = new Product();
prod.ProductId = 2;
prod.Name = "RELIANCE";
products.Add(prod);
return products;
}
}
http://localhost:1050/WCFService1/ProductService.svc/SelectAllProducts
Web.config
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<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 if try using the above url blank is getting displayed can some one help me ???
thanks in advance ..
Do some change in interface
[ServiceContract(Namespace = "JsonpAjaxService")]
interface IService
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
method()
}
add some code on class like below
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service1 : IService
your web.config file like this
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<authentication mode="None" />
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<standardEndpoints>
<webScriptEndpoint>
<standardEndpoint name="" crossDomainScriptAccessEnabled="true"/>
</webScriptEndpoint>
</standardEndpoints>
</system.serviceModel>
</configuration>
I don't see the service binding the web.config. Try adding line such as below:
<services>
<service name="[Your Namespace].ProductService">
<endpoint address="" binding="webHttpBinding" contract="[Your Namespace].IProductService" />
</service>
</services>
Its important that you use webHttpBinding for REST WCF Services. Also you need to attach webHttpBehavior - that's possible by using WebServiceHostFactory in your svc file. For example,
<%#ServiceHost Language="C#" Service="[YourNameSpace].ProductService" Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>
See below for more info:
http://saravananarumugam.wordpress.com/2011/03/04/simple-rest-implementation-with-webhttpbinding/
http://msdn.microsoft.com/en-us/magazine/dd315413.aspx