WCF REST Failed Network Error when writing directly to HttpResponse - wcf

I am creating a WCF REST webservice that will be used to download large files (potentially more than 2GB). The files are csv files that are not stored on a hard drive, instead they are formed in runtime when the request is made. Because of that I chose to write csv file directly into HttpResponse avoiding any intermediate containers that will not hold more than 2GB of data. This is a test code I wrote that does what I've described:
[ServiceContract]
public interface IDownloadService
{
[OperationContract]
[WebInvoke(
Method = "GET",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "")]
void Download();
}
public class DownloadService : IDownloadService
{
public void Download()
{
var response = HttpContext.Current.Response;
response.Clear();
response.ContentType = "application/csv";
response.AddHeader("Content-Disposition", "attachment; filename=myfile.csv");
//This is a small test csv file, it will be replaced with a big file,
//that will be formed in runtime and written piece by piece into Response.OutputStream
response.BinaryWrite(System.Text.Encoding.UTF8.GetBytes("1,2,3"));
response.Flush();
response.Close();
response.End();
}
}
This is my Web.config, just in case:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.6.1" />
<httpRuntime targetFramework="4.6.1"/>
</system.web>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="RestWcf.DownloadService">
<endpoint address="" binding="webHttpBinding" behaviorConfiguration="web" contract="RestWcf.IDownloadService"/>
</service>
</services>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
</configuration>
Now here's the interesting part when I call this webservice method from Google Chrome, first it starts downloading the file and at the end of the downloading Chrome gives me the error Failed - Network error, when I try to call it from Postman I get Could not get any response message with no response generated, finally when I try to call it from Fiddler I get 504 response with more informative message ReadResponse() failed: The server did not return a complete response for this request. Server returned 384 bytes.
Any ideas on what's going on here and how can I fix this weird behavior?

Related

WCF WebService Not Returning DataTable

I am beginning to use WCF to write a web service instead of the old asp.net asmx way. I want to be able to return JSON so I can't do it the old way. If I am returning a string or int the Web Service works fine but if I try to return a DataTable it becomes unresponsive and I get nothing. I have tried debugging to see where it blows up and it won't even stop on a breakpoint.
My Class file looks like this:
public string XMLData(string id)
{
return "You requested " + id;
}
public string JSONData(string id)
{
return "You requested " + id;
}
public DataTable TestDT()
{
DataTable Testing = new DataTable("TestDT");
return Testing;
}
My interface file looks like this:
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "xml/{id}")]
string XMLData(string id);
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "json/{id}")]
string JSONData(string id);
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "testdt/")]
DataTable TestDT();
The json method as well as the xml method works perfectly fine. When I call TestDT I get a standard IE Page showing no connectivity. I have tried it with data or no data in the datable with the same results.
One other note here: when I run the WCF service locally (Hitting PLAY) my test application shows now services I see this:
How can I get this to work with a datable?
Edit#1: I actually resolved the issue with the data not returning. I finally gave up on trying to return a dataset and instead I created a jagged array and ended up return it as JSON. I'll post it later as an answer so people know how I did it. What I am more interested in knowing now is part 2. Why is my WCF Test Client not showing any methods (see image attached) My hunch is its related to the web.config so I am posting that below:
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="DBDjuggleWS" connectionString="Data Source=localhost;Initial Catalog=PrayUpDev;Persist Security Info=True;User=DjuggleMaster;Password=DJPassword!" providerName="System.Data.SqlClient"/>
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name ="PrayUpService.PrayUp" behaviorConfiguration="ServiceBehaviour">
<endpoint address="" binding="webHttpBinding" contract="PrayUpService.IPrayUp" behaviorConfiguration ="web"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehaviour">
<!-- 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="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
you shoud return DataSet instead of DataTable but Returning data sets from web services is not typically considered a “good practice”. here you can read about it:
Why returning dataset or data table from WCF service is not a good practice? What are the Alternatives?
i highly recommend use the DataSet’s methods to get the data in XML format and pass the XML string instead of the DataSet itself to the service.
PassDataSet(dsDataSet.GetXmlSchema(), dsDataSet.GetXml())

WCF returns Bad Request on jquery ajax call

I have a WCF Service with one GET and one POST method. The GET works well.
The frontend is a simple HTML page which uses jquery ajax calls to GET and POST methods of the WCF.
The problem is that i get a Bad Request response. I have read all of the relative posts and i think that everything is in order, as far as i can tell.
Sources:
My contracts:
[OperationContract]
[WebGet(UriTemplate = "schedule?week={week}",
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare)]
[Description("Return the food schedule; specify the dates to include.")]
WeeklySchedule GetSchedule(int week);
[OperationContract]
[WebInvoke(UriTemplate="writeweek", Method = "POST",
RequestFormat=WebMessageFormat.Json,
ResponseFormat=WebMessageFormat.Json,
BodyStyle=WebMessageBodyStyle.Bare)]
[Description("Write or Update a week schedule via json data with POST")]
int WriteWeek(string jsonwk);
I have a separate Data Access Layer which does the write/read in DB and works fine.
My page source regarding the ajax calls:
function ajaxGetWeek(wk)
{
$.ajax({
cache: false,
type: "GET",
processData: false,
url: 'http://appsrv01/food/svc/foodland.svc/schedule?week='+ wk,
dataType: "json",
success: function(data) {
GetWeekSucceeded(data);
},
error: function (xhr,status,error) {
alert(error);
}
});
This works fine, it returns json format and i am able to parse it in my form.
POST ajax call that returns bad request:
function SubmitFood() {
var features = new Object(); // Create empty javascript object
features["weeknumber"] = currentWeek;
$("#TheForm textarea").each(function() { // Iterate over inputs
features[$(this).attr("name")] = $(this).val(); // Add each to features object
});
var jsontxt = JSON.stringify(features);
$.ajax({
type: "POST",
url: 'http://appsrv01/food/svc/foodland.svc/writeweek',
data: jsontxt,
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function(postresult) {
WriteWeekSucceeded(postresult);
},
error: function (xhr,status,error) {
alert(error);
}
});
}
The above returns something like:
{"weeknumber":24,"DishMon":"sdfadsf","DishTue":"asdfasd","DishWed":"fasdfa","DishThu":"sdfasdfas","DishFri":"dfasdf"}
i have put breakpoints in my VS solution but it dsoesnt even get to call the method.
my app.config:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true"/>
</system.web>
<!-- When deploying the service library project, the content of the config file must be added to the host's
app.config file. System.Configuration does not support config files for libraries. -->
<system.serviceModel>
<services>
<service name="FoodLandService.FoodLandService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:6969/FoodLand"/>
</baseAddresses>
</host>
<endpoint address=""
binding="webHttpBinding"
contract="ContractsClass.IFoodLandService"
behaviorConfiguration="Web" />
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="Web">
<webHttp helpEnabled="true"/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" />
<serviceDebug includeExceptionDetailInFaults="False"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
web.config:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="false" targetFramework="4.0" />
<customErrors mode="Off"/>
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
and foodland.svc:
<%# ServiceHost Service="FoodLandService.FoodLandService"
Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>
My Service source:
public class FoodLandService : ContractsClass.IFoodLandService
{
public WeeklySchedule GetSchedule(int week)
{
FoodClassDB fd = new FoodClassDB();
return fd.ReadWeekDB(week);
}
public int WriteWeek(string jsonwk)
{
FoodClassDB fd = new FoodClassDB();
return fd.WriteWeekDB(jsonwk);
}
}
json is encoded fine and i cant find a reason for my error.

Enabling WCF Help page changes response from JSON to XML

I'm working on creating a WCF web service that communicates via JSON. I got the service to a point that it's working and I'm trying to set up the help page so the developers that will consume the service can have some documentation to work by.
The issue that I'm running into is that when I did get the help page up and running, all the responses being sent out by my service changed from JSON to XML.
I'll be the first to admit that I'm very new to this. There might be some fundamental flaw with how I've structured my service, or it might be as simple as a flag I missed in the web.config... I'm really at a loss at this point.
What I found, through basically just trial and error and beating my head against the wall, was if I change the name attribute of the following line in the Web.config:
<standardEndpoint name="serviceEndpoint" helpEnabled="true" automaticFormatSelectionEnabled="true">
To be empty string:
<standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true">
The help page magically shows up, but my services are now spitting out XML instead of JSON.
I think it's probably better to over-share than to under-share for something as specific as this, so here's what I think is the relevant bits of the set-up. I apologize for the mono-tone code, I can edit it to be more readable if I figure out how.
Service Interface:
[OperationContract]
[Description("DESCRIPTIONATION HAPPENS")]
[WebInvoke(Method = "GET",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "GetYears")]
GetYearsReply GetYears();
...
Service Implementation:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MPG : IMPG
{
public GetYearsReply GetYears()
{
GetYearsReply reply = new GetYearsReply();
reply.YearList = generateYears();
return reply;
}
...
Global.asax:
<%# Application Codebehind="Global.asax.cs" Inherits="MPG_Service.Global" Language="C#" %>
Global.asax.cs:
namespace MPG_Service
{
public class Global : System.Web.HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes();
}
private void RegisterRoutes()
{
RouteTable.Routes.Add(new ServiceRoute("garage", new WebServiceHostFactory(), typeof(MPG)));
}
}
}
Web.config:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</modules>
</system.webServer>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
<standardEndpoints>
<webHttpEndpoint>
<!--
Configure the WCF REST service base address via the global.asax.cs file and the default endpoint
via the attributes on the <standardEndpoint> element below
-->
<standardEndpoint name="serviceEndpoint" helpEnabled="true" automaticFormatSelectionEnabled="true">
<!--<security mode="Transport">
<transport clientCredentialType="None"/>
</security>-->
</standardEndpoint>
</webHttpEndpoint>
</standardEndpoints>
</system.serviceModel>
</configuration>
If anyone has any insight into why this behavior is happening, or any other major screw-ups in my code I'd love any input.
Your client is saying that it accepts XML (application/xml), so that's what WCF is returning. That is consistent with the Automatic Formatting rules (see details at http://msdn.microsoft.com/en-us/library/ee476510.aspx). If you don't want that behavior, then set autoFormatSelectionEnabled to false in your configuration.

The very barest possible RESTful WCF service call with streams

I want to make a web service with the following properties:
It uses WCF and .NET 4.0
It is hosted in IIS7
It is RESTful
It's okay to keep the default output behaviour of collecting and handling WebFaultExceptions etc
It has a single call that
eats naked HTTP POST of potentially huge binary files (should preferably not be kept in memory!)
accepts a Stream as an input
outputs a Stream
uses an UriTemplate for matching (there will be more calls soon)
wants the streams to be completely raw and NOT have IIS or WCF try to be smart by handling the content type in any way
The problem is that IIS and/or WCF keep interfering regarding the Content-Type, insisting on returning
415 Cannot process the message because the content type '...' was not the expected type 'text/xml; charset=utf-8'
no matter what the content type was. Can you spot any errors I have made below?
[ServiceContract]
public interface IRenderService
{
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "/render", BodyStyle = WebMessageBodyStyle.Bare)]
Stream Render(Stream input);
}
With the following snippets from Web.config:
<system.web>
<compilation debug="true" targetFramework="4.0" />
<httpRuntime maxRequestLength="500000000" />
</system.web>
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding
name="FileStreamConfiguration"
transferMode="Streamed"
maxReceivedMessageSize="500000000"
maxBufferSize="500000000"
openTimeout="00:25:00"
closeTimeout="00:25:00"
sendTimeout="00:25:00"
receiveTimeout="00:25:00" />
</webHttpBinding>
</bindings>
<services>
<service name="RenderService" behaviorConfiguration="RenderServiceBehavior">
<endpoint address="" binding="webHttpBinding" contract="RenderServer.IRenderService" bindingConfiguration="FileStreamConfiguration" behaviorConfiguration="RenderEndpointBehaviour" >
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="RenderServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="RenderEndpointBehaviour">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
I want to always get the raw contents of the HTTP POST body, and fetch headers from WebOperationContext.Current.IncomingRequest manually if I deem that necessary, and IIS/WCF should completely ignore all aspects of the request besides parsing it and sending it to my code. I'll use WebOperationContext.Current.OutgoingResponse to set aspects of the output as I see fit, also manually.
This is so easy to do with the new WCF Web API library. See http://wcf.codeplex.com I have a sample on my blog which I will post once the power comes back on :-)
The interface looks like this,
[ServiceContract]
public interface IRenderService{
[WebInvoke(Method = "POST", UriTemplate = "/render")]
HttpResponseMessage Render(HttpRequestMessage input);
}

How to use a WCF service with HTTP Get (within Visual studio 2010)

We've tried to use a very very simple WCF service with a HTTp Get and we can't get it work.
We've followed those "guide" but it doesn't work
http://msdn.microsoft.com/en-us/library/bb412178.aspx
http://www.dotnetfunda.com/articles/article779-simple-5-steps-to-expose-wcf-services-using-rest-style-.aspx
When we call our service with the following url, we get a page not found error:
http://localhost:9999/Service1.svc/GetData/ABC
The base url (http://localhost:9999/Service1.svc) works fine and returns the wcf service information page correctly.
Those are the steps and code to reproduce our example.
In Visual Studio 2010, create a new "WCF Service Application" Project
Replace the IService interface with this code
[ServiceContract()]
public interface IService1
{
[OperationContract()]
[WebInvoke(Method = "GET",
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "GetData/{value}")]
string GetData(string value);
}
Replace the Service class with this code
public class Service1 : IService1
{
public string GetData(string value)
{
return string.Format("You entered: {0}", value);
}
}
The web.config look like this
<system.web>
<compilation debug="true" strict="false" explicit="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="Service1">
<endpoint address="" binding="webHttpBinding" contract="IService1" behaviorConfiguration="WebBehavior1">
</endpoint>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="WebBehavior1">
<webHttp helpEnabled="True"/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
Press Run and try to call the Get method
If someone get this or something similar working, it would be very kind if you could reply information about the working example.
Thank you very much
I recreated your sample - works like a charm.
One point: do your service contract (public interface IService1) and service implementation (public class Service1 : IService1) exist inside a .NET namespace??
If so, you need to change your *.svc and your web.config to include:
<services>
<service name="Namespace.Service1">
<endpoint address="" binding="webHttpBinding"
contract="Namespace.IService1"
behaviorConfiguration="WebBehavior1">
</endpoint>
</service>
</services>
The <service name="..."> attribute and the <endpoint contract="..."> must include the .NET namespace for this to work.