When I host my wcf service via webiste iis7, the method AfterReceiveRequest does not get called.
Please help..
Thanks
public class CultureMessageInspector : IClientMessageInspector, IDispatchMessageInspector
{
private const string HeaderKey = "culture";
#region IDispatchMessageInspector Members
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
int headerIndex = request.Headers.FindHeader(HeaderKey, string.Empty);
if (headerIndex != -1)
{
Thread.CurrentThread.CurrentCulture = new CultureInfo(request.Headers.GetHeader<String>(headerIndex));
}
return null;
}
public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
}
#endregion
#region IClientMessageInspector Members
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
}
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
request.Headers.Add(MessageHeader.CreateHeader(HeaderKey, string.Empty, Thread.CurrentThread.CurrentCulture.Name));
return null;
}
#endregion
}
My Behavior Extension class, Service.svc, and config settings are as follows:
<system.serviceModel>
<services>
<service name="C:\Visual Studio 2010\WebSites\WCFService8">
<endpoint binding="netTcpBinding" bindingConfiguration="" behaviorConfiguration="Default" contract="CultureServer.IHelloWorld" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="Default">
<CultureExtension/>
</behavior>
</endpointBehaviors>
<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>
<extensions>
<behaviorExtensions>
<add name="CultureExtension" type="Extension.CultureBehaviorExtension, Extension, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
public class CultureBehaviorExtension : BehaviorExtensionElement
{
// BehaviorExtensionElement members
public override Type BehaviorType
{
get { return typeof(CultureBehaviour); }
}
protected override object CreateBehavior()
{
return new CultureBehaviour();
}
}
<%# ServiceHost Language="C#" Debug="true" Service="CultureServer.Server"%>
<services>
<service name="C:\Visual Studio 2010\WebSites\WCFService8">
<endpoint binding="netTcpBinding" bindingConfiguration="" behaviorConfiguration="Default" contract="CultureServer.IHelloWorld" />
</service>
</services>
The name attribute for the <service> tag is wrong. It should have the class name, not a path. Try replacing it with the code below.
<services>
<service name="CultureServer.Server">
<endpoint binding="netTcpBinding" bindingConfiguration="" behaviorConfiguration="Default" contract="CultureServer.IHelloWorld" />
</service>
</services>
Related
I'm writing a WCF REST service to receive AWS SNS Notification Message with my WCF REST Service.
However, WCF REST only supports XML and JSON, but because of legacy reasons Amazon SNS posts their notifications with the Content-Type: text/plain; charset=UTF-8 header, according to the Amazon documentation:
POST / HTTP/1.1
Content-Type: text/plain; charset=UTF-8
// ...
{
"Type" : "Notification",
// ...
"UnsubscribeURL" : "https://sns.us-west-2.amazonaws.com/?Action=Unsubscribe&..."
}
When I call my service with this "text/plain" content type like Amazon, there is an error which says:
Request Error.
The server encountered an error processing the request. The exception message is 'The incoming message has an unexpected message format 'Raw'. The expected message formats for the operation are 'Xml'; 'Json'. This can be because a WebContentTypeMapper has not been configured on the binding. See the documentation of WebContentTypeMapper for more details.'. See server logs for more details.
My current code:
public interface MyServiceInterface
{
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "/AmazonIPChanges")]
Task AmazonIPChanges(SNSNotificationMessage data);
}
[DataContract]
public class SNSNotificationMessage
{
[DataMember]
public string Type { get; set; }
// ...
[DataMember]
public string UnsubscribeURL { get; set; }
}
The DataContract maps to the Amazon SNS message. This code is working when I perform a POST with content-type "application/json", but how can I let it accept Amazon's text/plain content-type?
You can fix this, as the error message indicates, by creating and applying a custom WebContentTypeMapper. It should look like this:
namespace StackOverflow36216464
{
public class RawContentTypeMapper : WebContentTypeMapper
{
public override WebContentFormat GetMessageFormatForContentType(string contentType)
{
switch (contentType.ToLowerInvariant())
{
case "text/plain":
case "application/json":
return WebContentFormat.Json;
case "application/xml":
return WebContentFormat.Xml;
default:
return WebContentFormat.Default;
}
}
}
}
This one interprets the content-type of the request, and returns the appropriate WebContentFormat enum member.
You can then apply it to your service in the form of a custom binding:
<system.serviceModel>
<bindings>
<customBinding>
<binding name="textPlainToApplicationJson">
<webMessageEncoding webContentTypeMapperType="StackOverflow36216464.RawContentTypeMapper, StackOverflow36216464, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<httpTransport manualAddressing="true" />
</binding>
</customBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="debugServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="restEndpointBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service
name="StackOverflow36216464.Service1"
behaviorConfiguration="debugServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:65393/"/>
</baseAddresses>
</host>
<endpoint address=""
binding="customBinding"
contract="StackOverflow36216464.IService1"
behaviorConfiguration="restEndpointBehavior"
bindingConfiguration="textPlainToApplicationJson"/>
</service>
</services>
</system.serviceModel>
The relevant part being the <customBinding> element, where the custom mapper is configured, and the servcices/service/endpoint/bindingConfiguration attribute where it is applied.
As far as I can tell I have mimicked the accepted solutions of this post and this post. Unless I'm blind (and I hope I am at this point), I have a spotless app.config for my very simple WCF service:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="RESTBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="Vert.Host.VertService.RSVPService">
<endpoint
address="/RSVP"
binding="webHttpBinding"
contract="Vert.Host.VertService.IRSVP"
behaviorConfiguration="RESTBehavior" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/Vert" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
Here's the corresponding Service Contract and Implementation:
namespace Vert.Host.VertService
{
[ServiceContract]
public interface IRSVP
{
[OperationContract]
bool Attending();
[OperationContract]
bool NotAttending();
}
public class RSVPService : IRSVP
{
public bool Attending()
return true;
public bool NotAttending()
return true;
}
}
I'm hosting everything via a console app:
class Program
{
public static void Main()
{
// Create a ServiceHost
using (ServiceHost serviceHost = new ServiceHost(typeof(RSVPService)))
{
serviceHost.Open();
// The service can now be accessed.
Console.ReadLine();
}
}
}
All I want to do is stand this tiny service up, but I can't hit this endpoint with http://localhost:8080/Vert/RSVP/Attending. I still get 405 Method not allowed as a response.I'm using Visual Studio Community 2015, IIS10, targeting .NET 4.6
Things I've tried from suggestions:
I've given my service an explicitly-named behavior. No luck.
What am I missing?
Honestly not sure if this will make the difference, but mine has a link to service behaviour. Give your service behaviour a name:
<serviceBehaviors>
<behavior name="ServiceBehavior">
Then link it to your service:
<service name="Vert.Host.VertService.RSVPService" behaviorConfiguration="ServiceBehavior">
Be sure to decorate the service methods with the [WebGet] attribute (reference System.ServiceModel.Web.dll)
I.e. changing the service from
public class RSVPService : IRSVP
{
public bool Attending()
return true;
public bool NotAttending()
return true;
}
to
public class RSVPService : IRSVP
{
[WebGet]
public bool Attending()
return true;
[WebGet]
public bool NotAttending()
return true;
}
Solves the issue.
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.
Im trying to combine SOAP and REST under one roof with some modification. But I dont know whether its possbile. My code is below, it used to work when REST only but since I tried to add the extra web service as SOAP (using configuration) it doesnt work. Not sure how to configure it...
I have the interfaces:
[ServiceContract]
public interface IVLSContentServiceREST
{
[OperationContract]
[WebGet]
string EchoWithGet(string s);
[OperationContract]
[WebInvoke]
string EchoWithPost(string s);
}
[ServiceContract]
public interface IVLSContentServiceSOAP
{
[OperationContract]
[WebGet]
string EchoWithGet(string s);
[OperationContract]
[WebInvoke]
string EchoWithPost(string s);
}
Then I have a file called VLSContentService.svc with this:
<%# ServiceHost Language="C#" Debug="true" Service="VLSContentService" CodeBehind="VLSContentService.svc.cs" %>
And the cs(codebehind) file:
public class VLSContentService : IVLSContentServiceSOAP, IVLSContentServiceREST
{
string IVLSContentServiceSOAP.EchoWithGet(string s)
{
return "You said " + s;
}
string IVLSContentServiceSOAP.EchoWithPost(string s)
{
return "You said " + s;
}
string IVLSContentServiceREST.EchoWithGet(string s)
{
return "You said " + s;
}
string IVLSContentServiceREST.EchoWithPost(string s)
{
return "You said " + s;
}
}
And the configuration:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<!---Add the service-->
<services>
<service behaviorConfiguration="VLSContentServiceBehaviour" name="VLSContentService">
<endpoint address="rest" behaviorConfiguration="VLSContentServiceEndpointBehaviour" binding="webHttpBinding" contract="IVLSContentServiceREST"/>
<endpoint address="soap" behaviorConfiguration="VLSContentServiceEndpointBehaviour" binding="basicHttpBinding" contract="IVLSContentServiceSOAP"/>
</service>
</services>
<!---Add the behaviours-->
<behaviors>
<serviceBehaviors>
<behavior name="VLSContentServiceBehaviour">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<!---Add the behaviours-->
<endpointBehaviors>
<behavior name="VLSContentServiceEndpointBehaviour">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
You don't need two versions of the contract - just host the same contract at two endpoints using different bindings
<services>
<service behaviorConfiguration="VLSContentServiceBehaviour" name="VLSContentService">
<endpoint address="rest" behaviorConfiguration="VLSContentServiceEndpointBehaviour" binding="webHttpBinding" contract="IVLSContentService"/>
<endpoint address="soap" behaviorConfiguration="VLSContentServiceEndpointBehaviour" binding="basicHttpBinding" contract="IVLSContentService"/>
</service>
</services>
I am attempting to create and host a simple RESTful WCF Service. The service works perfectly except for 1 situation. I attempt to perform a POST to insert a new object into my static List using the JSON request of:
{"sampleItem":{"Id":1,"StartValue":2,"EndValue":3}}
If I then change the request to be:
{"sampleItemBlah":{"Id":1,"StartValue":2,"EndValue":3}}
I get a 500 response and all future POST's return a 500 error until I recycle my IIS App Pool and then it starts to work again.
It doesn't appear that the service is in a faulted state because I can still perform GET's and get data back. I turned on trace debugging and I do not see any errors in my log file.
Does anyone have any ideas?
Here is my Service Contract:
[ServiceContract]
public interface IWcfRestService
{
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
[OperationContract]
SampleItem Insert(SampleItem sampleItem);
}
[DataContract]
public class SampleItem
{
[DataMember]
public int Id { get; set; }
[DataMember]
public int StartValue { get; set; }
[DataMember]
public int EndValue { get; set; }
}
And here is my implementation:
public class WcfRestService : IWcfRestService
{
private static readonly List<SampleItem> Items = new List<SampleItem>();
public SampleItem Insert(SampleItem sampleItem)
{
return BaseInsert(sampleItem);
}
private static SampleItem BaseInsert(SampleItem sampleItem)
{
if (Items.Exists(x => x.Id == sampleItem.Id))
Items.RemoveAll(x => x.Id == sampleItem.Id);
Items.Add(sampleItem);
return sampleItem;
}
}
And finally here is my ServiceModel section of my Web.config:
<services>
<service behaviorConfiguration="Services.ServiceBehavior"
name="WcfRestServiceApp.WcfRestService">
<endpoint address=""
behaviorConfiguration="RESTBehavior"
binding="webHttpBinding"
contract="WcfRestServiceApp.IWcfRestService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="RESTBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="Services.ServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
Any and all help is greatly appreciated.
It turned out that the problem was with using the tag:
BodyStyle = WebMessageBodyStyle.Wrapped
When I removed it, the requirement to have:
{"sampleItem":{"Id":1,"StartValue":2,"EndValue":3}}
turned into:
{"Id":1,"StartValue":2,"EndValue":3}
This forced the cast to the correct object type and if the field wasn't present, it set the value to null or the type's default empty value.