C# 4.0 WCF REST JSON - HTTP GET CODE 400 Bad Request - wcf

When trying to create a simple service to return a simple JSON string by following several tutorials. I get stuck on two different machines with a HTTP Statuscode 400 bad request.
Example tutorials
RESTful WCF Service with JSON pt.1 & pt.2 - http://www.youtube.com/watch?v=5BbDxB_5CZ8
I have also Google and searched here (StackOverflow) for similar problem without success.
The problem is I get the 400 bad request when trying to do a sanity check to browse to the WCF service and execute the method. By compiling the service and browse this address: http://localhost:49510/Service1.svc/GetPerson
Just like the tutorial. I have tried finding a solution for like 3 days. Any help is appreciated.
This is what I do.
First i create a new project a simple WCF Service application. I delete the default Service1.svc and add a new WCF Service, that generate a new Service1.svc and a IService1.cs
Here is the code for the interface (IService1.cs)
namespace WcfService1
{
// 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="GET", BodyStyle=WebMessageBodyStyle.Bare, ResponseFormat=WebMessageFormat.Json, RequestFormat=WebMessageFormat.Json, UriTemplate="GetPerson")]
Person GetPerson();
}
[DataContract(Name="Person")]
public class Person
{
[DataMember(Name="name")]
public string Name { get; set; }
}
}
Here is the code for the Service1.svc
namespace WcfService1
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
public class Service1 : IService1
{
public Person GetPerson()
{
return new Person() { Name = "Tobbe" };
}
}
}
And the Web.config is untouched and look likes this 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>

For REST WCF You have to do binding and endpoint setting in web.config
Replace your whole web.config by following and it will work
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<protocolMapping>
<add scheme="http" binding="webHttpBinding"/>
</protocolMapping>
<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>
<endpointBehaviors>
<behavior>
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
You were remaining with following 2 things
Use webHttpBinding (change default http port mapping to webHttpBinding)
<system.serviceModel>
<protocolMapping>
<add scheme="http" binding="webHttpBinding"/>
</protocolMapping>
<behaviors>
<system.serviceModel>
Specify webHttp End Point Behaviors
<system.serviceModel>
-----
</protocolMapping>
<behaviors>
<endpointBehaviors>
<behavior>
<webHttp />
</behavior >
</endpointBehaviors>
<behaviors>
------
<system.serviceModel>

You didn't specify any endpoint... By default on WCF 4, an endpoint using basicHttpBinding will be used. It'll not work here because it is a SOAP-based binding. What you want to use is webHttpBinding which is REST-based...
Here is how to override default binding with WCF 4 :
<system.serviceModel>
<protocolMapping>
<add scheme="http" binding="webHttpBinding"/>
</protocolMapping>
</system.serviceModel>
You also have to enable webHttp by adding this endpoint behavior in your config :
<behaviors>
<endpointBehaviors>
<behavior>
<webHttp />
</behavior >
</endpointBehaviors>
<behaviors>
http://msdn.microsoft.com/en-us/library/bb924425.aspx

I'm not entirely sure why, but when I added the 'Factory' attribute to my .SVC file (you need to explicitly drag it to Visual Studio), everything just works - without any changes to default settings in Web.config!
I added Factory="System.ServiceModel.Activation.WebServiceHostFactory" so my .SVC file went from this:
<%# ServiceHost Language="C#" Debug="true" Service="ServiceNameSpace.ServiceName" CodeBehind="ServiceName.svc.cs" %>
to this:
<%# ServiceHost Language="C#" Debug="true" Service="ServiceNameSpace.ServiceName" CodeBehind="ServiceName.svc.cs" Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>
The only side effect seems to be that when you click on the .SVC file in the browser, you get an 'Endpoint not found' error, but the service works fine when you invoke it correctly anyway. As mentioned previously, I'm using a default Web.config with .NET 4.6 (Simplified WCF configuration), so I may yet need to add endpoint details for that to work again.
Note to moderator: my apologies for posting this answer on a couple of questions. Won't do it again. However, I don't think that deleting it from BOTH questions was very balanced. This is why I have re-posted this answer here only.

Related

Does Visual Studio Online support SOAP WorkItem change notification?

The reason I ask, is that I've set up a WCF service following the guidance out there (specifics below), and set up a SOAP notification in Visual Studio Online and my service doesn't appear to be called. IIS 8.5 Logs show no attempt to make contact with the service from VSO servers.
In case it IS supported, here are relevant bits to see if I have something set up wrong on the service side.
WCF Service - .NET 4.5.1 hosted as an Azure WebRole
Contract and Implementation
[ServiceContract(Namespace = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03")]
public interface IWorkItemSubscriber
{
[OperationContract(Action = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify")]
[XmlSerializerFormat(Style = OperationFormatStyle.Document)]
void Notify(string eventXml, string tfsIdentityXml);
}
// Note, I've tried w/ and w/out this Compatibility Attribute
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class WorkItemSubscriber : IWorkItemSubscriber
{
public void Notify(string eventXml, string tfsIdentityXml)
{
// Do stuff
}
}
Web.Config
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5.1" />
<customErrors mode="Off"/>
</system.web>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="noSecurity">
<security mode="None" />
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="VsoNotificationService.Wcf.WorkItemSubscriber" behaviorConfiguration="eventServiceBehavior">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="noSecurity" contract="VsoNotificationService.Wcf.IWorkItemSubscriber" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="eventServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" aspNetCompatibilityEnabled="true" /> <!-- note: I've tried w/ and w/out the aspNetCompatibilityEnabled attribute -->
</system.webServer>
</configuration>
Visual Studio Online Configuration
I've confirmed I can hit the service, via creating my own client and calling the service. Whatever code I put in the method is executed, and if I do remote debugging via Visual Studio 2013 I'll hit the method's breakpoint. So the service is up and running, I just don't see traffic from Visual Studio Online (via code breakpoint, code content, nor IIS Logs). Makes me think that feature is not working there?
I see that you are missing the aspNetCompatibilityEnabled="true" on the <serviceHostingEnvironment element, as compared to my working solution, it might be the missing piece of the puzzle?
I only also achieved success by carefully including all little config settings.

Castle WCF Integration Facility

I’m trying to use Castle WCF integration facility in my project. I followed instructions from the castle official site http://docs.castleproject.org/Windsor.WCF-Facility-Registration.ashx
But I couldn't make it work. Here's my code and configuration.
protected void Application_Start(object sender, EventArgs e)
{
BuildContainer();
}
private void BuildContainer()
{
Container = new WindsorContainer();
//1st
Container.Kernel.AddFacility<WcfFacility>();
Container.Kernel.Register(Component.For<IProductService>()
.ImplementedBy<ProductService>()
.Named("ProductService"));
//2nd
Container.AddFacility<WcfFacility>()
.Install(Castle.Windsor.Installer.Configuration.FromXmlFile("Castle.config"));
//3rd
Container.Register(
Component.For<IProductService>()
.ImplementedBy<ProductService>()
.LifeStyle.PerWcfOperation()
.AsWcfService(new DefaultServiceModel()
.AddEndpoints(WcfEndpoint.BoundTo(new WSHttpBinding(SecurityMode.None)
{
MaxReceivedMessageSize = Int32.MaxValue,
MaxBufferPoolSize = Int32.MaxValue,
ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas
{
MaxStringContentLength = Int32.MaxValue
}
}).At("http://localhost:1278/ProductService")
)
.AddBaseAddresses("http://localhost:1278/ProductService")
.PublishMetadata()
));
}
As you can see above I've tried to register my service in 3 different ways. To be clear I run only one of those 3 registration code at a time, the others are commented out. For the one which gets config from castle.config here is my castle.config :
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<components>
<component id="TestService"
service="IProductService"
type="ProductService"
lifestyle="transient">
</component>
</components>
</configuration>
And lastly here is my web.config
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<services>
<service name="WCFLibrary.ProductService">
<endpoint name ="IProductService_Endpoint" address="http://localhost:1278/ProductService" binding="httpBinding" contract="WCFLibrary.IProductService" />
</service>
</services>
</system.serviceModel>
</configuration>
Many thanks for any help...
you may be registering your services, but not to the Windsor kernel that is used in the DefaultServiceHostFactory from the Castle WcfFacility.
IMO the easiest way is to create a custom Service Host Factory, deriving from DefaultServiceHostFactory. One elegant way to register your services to the kernel before the service instance itself is created is shown here: http://blog.ploeh.dk/2010/05/18/SneakViewAtCastlesWCFFacility.aspx . You will of course have to modify your .svc files to use your custom factory class instead of the DefaultServiceHostFactory, for instance:
<%# ServiceHost Language="C#" Service="MyService"
Factory="MyProject.MyServiceHostFactory, MyProject" %>
In essence, you pass your prepared container to the Constructor of DefaultServiceHostFactory which will then use the container to resolve the services and their dependencies.

cant get fiddler to record requests from wcftestclient.exe?

I build a very basic wcf service using visual studio development server just to see fiddler working:
c#
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
}
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>
when I run the wcftestclient it shows up the getdata() works but does not show up in fiddler? how can i amend this?
thanks
P
What is address of your service? If you use localhost or 127.0.0.1 these messages won't be captured. Use your machine name or network IP address. You can set it in Project properties or directly on the endpoint.

WCF HTTP 504 Error

I have the following problem. I am using Entity Framework to connect to a SQL Azure and that works(I tested it in a Test Project).
But when i try to get it through WCF RESTful service it throws Error 504.
My Operation Contract:
[ServiceContract]
public interface IService
{
[OperationContract]
[WebGet(UriTemplate = "/Artikli", ResponseFormat = WebMessageFormat.Json)]
IEnumerable<Artikal> GetArtikli();
}
Implementation of [ServiceContract] :
public class Service : IService
{
public IEnumerable<Artikal> GetArtikli()
{
using (var context = new CijenolomciEntities())
{
var result = context.Artikals.ToList();
result.ForEach(a => context.Detach(a));
return result;
}
}
}
The whole thing is hosted on local IIS. I use Fiddler, an what it says when i try to reach
http://localhost:17916/Service.svc/Artikli
is
[Fiddler] ReadResponse() failed: The server did not return a response for this request.
The WCF App.Config looks like:
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="CijenolomciEntities" connectionString="My_Connection_String" providerName="System.Data.EntityClient" />
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<protocolMapping>
<add scheme="http" binding="webHttpBinding" />
</protocolMapping>
<behaviors>
<endpointBehaviors>
<behavior>
<webHttp />
</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>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
EDIT:
When i try to access URL through browser i get the following:
Request Error
The server encountered an error processing the request. See server logs for more details.
Try to enable Tracing and see if your request is exceeding the default values due to which you are getting a timeout error.
Inspect the trace log for detailed error on why it is failing and then appropriately perform the needed steps to increase either the timeout values or the default size limits
If your network environment is set to make all HTTP traffic go through a proxy server then it's likely the account the IIS app pool is running under isn't allow to send HTTP traffic. As a test, change the app pool account to your login account and see if the WCF service connects successfully. The 504 message is usually a proxy or network issue.
I don't think it is the network error. The issue is in the service. Might be you receive 504 not from IIS, but from Fiddler. Read this. Might be you have to increase maxItemsInObjectGraph

aspNetCompatibilityEnabled="true"

I have made a Azure web app that has a ASP.NET web that also contains some JSON WCF services. I really don't know enough about WCF service models to be sure that I'm doing it right, does this look correct to you? Are there other service model configurations that is better for scalability, more maximum concurrent connections, etc?
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
</system.serviceModel>
<system.net>
<settings>
<!-- See http://social.msdn.microsoft.com/Forums/en-US/windowsazuredata/thread/d84ba34b-b0e0-4961-a167-bbe7618beb83 -->
<servicePointManager expect100Continue="false" />
</settings>
</system.net>
This works but I occasionally get unexpected connection drops (timeouts) with no HTTP error codes in my development environment which worries me.
Update # 24. Nov. 2011
web.config
<system.net>
<connectionManagement>
<!-- See http://social.msdn.microsoft.com/Forums/en-US/windowsazuredata/thread/d84ba34b-b0e0-4961-a167-bbe7618beb83 -->
<add address="*" maxconnection="48" />
</connectionManagement>
</system.net>
I'm suspecting that it may be the Visual Studio web server that causes the Ajax calls to get timeouts, after some minutes the service starts to accept requests again. Here is my complete setup, can you see what the problem is? I only have a single Ajax call to the service.
Inferface
IExample.cs:
using System.ServiceModel;
using System.ServiceModel.Web;
namespace WebPages.Interfaces
{
[ServiceContract]
public interface IExample
{
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json)]
string GetSomething(string id);
}
}
ExampleService.svc.cs markup
<%# ServiceHost Language="C#" Debug="true" Service="WebPages.Interfaces.ExampleService" CodeBehind="ExampleService.svc.cs" Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>
ExampleService.svc.cs codebehind
namespace WebPages.Interfaces
{
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ExampleService : IExample
{
string JsonSerializeSomething(Something something)
{
var serializer = new DataContractJsonSerializer(something.GetType());
var memoryStream = new MemoryStream();
serializer.WriteObject(memoryStream, something);
return Encoding.Default.GetString(memoryStream.ToArray());
}
public string GetSomething(string id)
{
var something = DoSomeBusinessLogic(id);
return JsonSerializeSomething(something);
}
}
}
jQuery call from client
function _callServiceInterface(id, delegate) {
var restApiCall = "Interfaces/ExampleService.svc/GetSomething?id="
+ escape(id);
$.getJSON(restApiCall, delegate);
}
function _getSomethingFromService() {
_callServiceInterface('123',
function (result) {
var parsedResult = $.parseJSON(result);
$('#info').html(result.SomethingReturnedFromServiceCall);
}
);
}
Update
I think I know what the problem is now; it seems that WCF services are single threaed by default ( source: http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k(SYSTEM.SERVICEMODEL.SERVICEBEHAVIORATTRIBUTE.CONCURRENCYMODE);k(TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV4.0%22);k(DevLang-CSHARP)&rd=true ) . That explain why my Ajax calls get timeouts, its blocked by another thread. This code should work a lot better:
ExampleService.svc.cs
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerSession,
IncludeExceptionDetailInFaults = false, MaxItemsInObjectGraph = Int32.MaxValue)]
//[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ExampleService : IExample
web.config
<system.serviceModel>
<protocolMapping>
<add scheme="http" binding="webHttpBinding" bindingConfiguration="" />
</protocolMapping>
<behaviors>
<endpointBehaviors>
<behavior name="">
<webHttp defaultOutgoingResponseFormat="Json" />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
ExampleService.svc
<%# ServiceHost Language="C#" Debug="true" Service="WebPages.Interfaces.TagService" CodeBehind="TagService.svc.cs" %>
Update # 9. Oct. 2011
I think I got the answer I needed here Locking with ConcurrencyMode.Multiple and InstanceContextMode.PerCall
aspNetCompatibilityEnabled="false" means not being able to access HttpContext, ASP.NET Sessions, etc. in my WCF code.
I think I got the answer I needed here Locking with ConcurrencyMode.Multiple and InstanceContextMode.PerCall
aspNetCompatibilityEnabled="false" means not being able to access HttpContext, ASP.NET Sessions, etc. in my WCF code.