Ok, so..
I have a WCF service that throws a WebFaultException<Error>(Error, HttpStatusCode.BadRequest) where Error is my custom, serializable object.
This all works as expected when I host the service on my local machine, and on GoDaddy's (as seen here: link removed).
But when hosted with Arvixe all I receive is a 'Bad Request' response (as seen here: link removed)
Analyzing the response headers, it appears that my local machine, GoDaddy, and Arvixe are all using the same .NET version. However, my local machine is running IIS 8.0, GoDaddy is running IIS 7.0, and Arvixe is running IIS 8.5.
So, what's causing the discrepancy? Does IIS 8.5 handle WebFaultException's differently? Nothing I find on the internet suggests it does. Or does IIS need to be configured to return WebFaultExceptions? Again, everything I read says it is configured entirely in the ASP Web.config.
Any other suggestions?
** EDIT **
I'm fairly certain this has to do with IIS and not my code, considering it works fine on my local machine (IIS8) and GoDaddy (IIS7), but not on Arvixe (IIS8.5)
Anyways, here's some snippets:
The error object I'm trying to return
[DataContract]
public class Error {
[DataMember]
public int Code { get; set; }
[DataMember]
public string Message { get; set; }
[DataMember]
public string Display { get; set; }
[DataMember]
public List<Error> Details { get; set; }
public Error(int code, string message, List<Error> details = null, string display = null) {
this.Code = code;
this.Message = message;
this.Display = display;
this.Details = details ?? new List<Error>();
}
}
Trying to return it to the client via:
throw new WebFaultException<Error>(new Error(802, "games/asdf"), HttpStatusCode.BadRequest);
The method I am trying to throw the WebFaultException from:
[OperationContract]
[WebInvoke(
Method = "GET",
UriTemplate = "/games/{game}/scores"
)]
List<Score> GetScores(string game);
I have tried adding a [FaultContract(typeof(Error))] attribute to the method but it had no effect.
Here's the Web.config registering my service
<?xml version="1.0"?>
<configuration>
<appSettings>
</appSettings>
<connectionStrings>
<!-- DEV -->
<add name="App" connectionString="XXX" />
<add name="Log" connectionString="XXX" />
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<webServices>
<protocols>
<clear />
<add name="HttpGet"/>
<add name="HttpPost" />
<add name="HttpPostLocalhost" />
</protocols>
</webServices>
<pages>
<namespaces>
<add namespace="System.Web.Optimization" />
</namespaces>
</pages>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<!--old-->
<behavior name="OldService">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
<!--new-->
<behavior name="V3">
<serviceAuthorization serviceAuthorizationManagerType="ScoresWs.V3.Auth, ScoresWs"/>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="REST">
<!--faultExceptionEnabled needs to be false or else we return .net exceptions as xml instead of our custom WebFaultException-->
<webHttp
helpEnabled="true"
faultExceptionEnabled="false"
automaticFormatSelectionEnabled="false"
defaultOutgoingResponseFormat="Json" />
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="defaultBinding" maxReceivedMessageSize="2097152">
<security mode="None" />
</binding>
</webHttpBinding>
</bindings>
<services>
<service name="ScoresWs.WebServiceV2" behaviorConfiguration="OldService">
<endpoint
address=""
binding="webHttpBinding"
behaviorConfiguration="REST"
bindingConfiguration="defaultBinding"
contract="ScoresWs.IWebServiceV2" />
</service>
<service name="ScoresWs.V3.Api" behaviorConfiguration="V3">
<endpoint
address=""
binding="webHttpBinding"
behaviorConfiguration="REST"
bindingConfiguration="defaultBinding"
contract="ScoresWs.V3.IApi"/>
</service>
</services>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<directoryBrowse enabled="false" />
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="WebGrease" publicKeyToken="31ad335" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Annnnnnd lastly I activate the webservices in my Global.asax:
public class Global : System.Web.HttpApplication {
protected void Application_Start(object sender, EventArgs e) {
RouteTable.Routes.Add(new ServiceRoute("api/v2", new WebServiceHostFactory(), typeof(ScoresWs.WebServiceV2)));
RouteTable.Routes.Add(new ServiceRoute("api/v3", new WebServiceHostFactory(), typeof(ScoresWs.V3.Api)));
}
}
Solved it! Like I suspected, it had nothing to do with my code.
In the Arvixe hosting panel I had to enabled "Show detailed ASP.NET errors in browser" (WebSites->Errors->ASP.NET). However, I'm not exactly sure what impact this has on security, since the Web.config hasn't changed and I can't see the IIS configuration.
Odd that the Arvixe support team wouldn't have directed me here immediately considering 'my detailed ASP.NET errors' weren't being sent to the client.
Related
So, I've made this web service(well WCF Service I guess) that inputs some parameters and returns a json object. This works pretty well.
But now I want to make some changes to the client.
Currently I just have a button, some textboxes for inputs, and a textarea.
The button looks like this:
ServiceReference1.Service1Client sc = new ServiceReference1.Service1Client();
protected void Button11_Click(object sender, EventArgs e)
{
int? i;
if (tbSagsNr.Text != "")
{
i = Convert.ToInt32(tbPOSTUdlSag.Text);
}
else
{
i = null;
}
string s = tbFacilitet.Text;
string a1 = tbAdresse1.Text;
string a2 = tbAdresse2.Text;
string p = tbPostNr.Text;
string json = sc.HouseSearch(i, s, a1, a2, p);
TextArea1.InnerText = json;
}
What do I do if I want to call the web service through the url instead? I'm thinking it should look something like this, depending on what parameters I use:
http://localhost:58637/Default.aspx/Service1.svc/HouseSearch?vSagsNr=5
Instead of textboxes and all that it should just print the json string directly on the screen.
I'm pretty new at making web services and I feel like I've kinda just been bumbling my way so far.
IService1:
[OperationContract()]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "HouseSearch")]
string HouseSearch(int? vSagsNr, string vFacilitet, string vAdresse1, string vAdresse2, string vPostNr);
Edit: Actually it should look more like this probably:
http://localhost:58637/WCFTest3/Service1.svc/HouseSearch?vSagsnr=5
Edit: My webconfig now looks like this:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.6.1" />
<httpRuntime requestPathInvalidCharacters="" requestValidationMode="2.0" targetFramework="4.6.1"/>
<pages validateRequest="false" />
</system.web>
<system.serviceModel>
<services>
<service behaviorConfiguration="WCFTest3_Behavior" name="WCFTest3.Service1">
<endpoint
address =""
binding="webHttpBinding"
bindingConfiguration="webHttpEndpointBinding"
name="WCFTest3.Service1"
contract="WCFTest3.IService1"
behaviorConfiguration="web"/>
<endpoint address="mex" binding="mexHttpBinding" bindingConfiguration="" name="mexEndPoint" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WCFTest3_Behavior">
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="false" />
<!-- 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>
<bindings>
<webHttpBinding>
<binding name="webHttpEndpointBinding">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</webHttpBinding>
</bindings>
<protocolMapping>
<add binding="webHttpBinding" scheme="http" />
</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>
<connectionStrings>
<add
name="UnikBoligCon"
connectionString="server=??;database=??;user=??;password=??"
providerName="System.Data.SqlClient"
/>
</connectionStrings>
</configuration>
But I get this error:
No base address found that matches the https form for the endpoint with the WebHttpBinding link. Registered base address schemas are [http].
Edit: Oh wait I guess I need to fill in the adress, services in the webconfig now looks like this
<services>
<service behaviorConfiguration="WCFTest3_Behavior" name="WCFTest3.Service1">
<endpoint
address ="http://localhost:58532/Service1.svc"
binding="webHttpBinding"
bindingConfiguration="webHttpEndpointBinding"
name="WCFTest3.Service1"
contract="WCFTest3.IService1"
behaviorConfiguration="web"/>
<endpoint address="mex" binding="mexHttpBinding" bindingConfiguration="" name="mexEndPoint" contract="IMetadataExchange"/>
</service>
</services>
And I've gotten rid of "multipleSiteBindingsEnabled="true"" because it threw an error and I don't think I need it.
Now getting this error though:
The authentication schemes configured on the host (Anonymous) do not allow those configured on the binding WebHttpBinding (“Anonymous”). Please ensure that the SecurityMode is set to Transport or TransportCredentialOnly. Additionally, this may be resolved by changing the authentication schemes for this application through the IIS management tool, through the ServiceHost.Authentication.AuthenticationSchemes property, in the application configuration file at the element, by updating the ClientCredentialType property on the binding, or by adjusting the AuthenticationScheme property on the HttpTransportBindingElement.
I have done something much the same as you described. A WCF service that can be switched (by changing the web.config) to serve Http, NetTCP, or REST. It was easy enough to get Http and NetTCP configs to sit side by side, but I was unable to figure out how to incorporate the REST config with the other two, so I kept them separate (and my requirements didn't call for a REST api, I just wanted to do it anyway).
My Operation Contract is:
[OperationContract]
[
WebInvoke(Method = "GET",
BodyStyle = WebMessageBodyStyle.Wrapped,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "TestMethod/{applicationCode}/?ignoreStatus={ignoreStatus}&logonName={logonName}&userProfileId={userProfileId}")
]
String TestMethod(String applicationCode, Boolean ignoreStatus = false, String logonName = "", String userProfileId = "");
Which can be called via a Url (tested using an Internet Browser).
http://localhost/JayVServerV2/DataAccess/DataAccess.svc/TestMethod/Tom?ignoreStatus=true&logonName=JayV&userProfileId
The most important part of the solution was getting the Web.Config setup correctly. So, I have included the whole of my Web.Config for you to see how I did it.
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5.2"/>
<httpRuntime targetFramework="4.5"/>
<authentication mode="Windows"/>
<authorization>
<allow users="*"/>
</authorization>
<identity impersonate="false"/>
</system.web>
<system.serviceModel>
<services>
<service behaviorConfiguration="JayVServer_Behavior" name="JayVServerV2.DataAccess.DataAccess">
<endpoint
address =""
binding="webHttpBinding"
bindingConfiguration="webHttpEndpointBinding"
name="RestJayVServerV2.DataAccess.DataAccess"
contract="DataServerV2.DAtaAccess.IDataAccess"
behaviorConfiguration="web"/>
<endpoint address="mex" binding="mexHttpBinding" bindingConfiguration="" name="mexEndPoint" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="JayVServer_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="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="webHttpEndpointBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</webHttpBinding>
</bindings>
<protocolMapping>
<add binding="webHttpBinding" scheme="http" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
I have a WCF service application set up so when I call the address it just returns true.
IRemoteService.cs
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "ValidationResult/")]
bool ValidationResult();
RemoteService.svc.cs
namespace RemoteService
{
public class RemoteService : IRemoteService
{
public bool ValidationResult()
{
return true;
//throw new NotImplementedException();
}
}
}
I have added an application on IIS and now I can access the service on the following url :
https://localhost/ValidationServiceApp/RemoteService.svc/validationresult/
This returns :
{"ValidationResultResult":true}
Works great. But when I run the following powershell script, I cant access the service :
$url = "https://localhost/ValidationServiceApp/SASRemoteService.svc/validationresult/"
$result = Invoke-RestMethod -Method GET -Uri $url
Write-Host $result
I must point out, I have tried on a client application called 'I'm only resting' and this returns whats expected. So I think it must be something to do with powershell. Either I haven't allowed something in the web.config file or some setting missing in powershell. I have also tried to ignore certificate errors on powershell. This didn't help.
Error from powershell :
Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send.
At line:18 char:11
+ $result = Invoke-RestMethod -Method GET -Uri $url
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
Here is the web.config file for the service :
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.6"/>
<httpRuntime targetFramework="4.6"/>
<httpModules>
<add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web"/>
</httpModules>
</system.web>
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="webHttpTransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None" />
</security>
</binding>
</webHttpBinding>
</bindings>
<services>
<service name="RemoteService.RemoteService" behaviorConfiguration="ServiceBehaviour">
<endpoint address =""
binding="webHttpBinding"
contract="RemoteService.IRemoteService"
bindingConfiguration="webHttpTransportSecurity"
behaviorConfiguration="web" />
<endpoint address="mex"
binding="mexHttpsBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehaviour">
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="false" 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>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<protocolMapping>
<add binding="webHttpBinding" scheme="https"/>
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<remove name="ApplicationInsightsWebTracking"/>
<add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web"
preCondition="managedHandler"/>
</modules>
<!--
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"/>
<validation validateIntegratedModeConfiguration="false"/>
</system.webServer>
</configuration>
Managed to find the problem.
I needed to edit permissions on the hosted service in IIS. So I added Users ({pcname}/Users) to the list of allowed users.
I would delete the question, but perhaps this may help someone in the future :)
I have created the WCF service and consumed that service into my client side application and I'm unable to invoke the method.
the following exception is occured:
{"The server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework SDK documentation and inspect the server trace logs."}
I think there is the some issue with the binding. I had googled but didn't find any solution. Please guide me how can I fix this issue. Help will be appreciate.
Thanks
Code Snippet:
Service 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>
<!-- 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>
<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>
Index.aspx
private void process()
{
TestRef.EmployeeDC o = new TestRef.EmployeeDC();
o.userID = signInEmail;
o.companyID = signInPassword;
//ServiceReference.EmployeeDC p = new ServiceReference.EmployeeDC();
//Service Call
TestRef.TestServClient tsc = new TestRef.TestServClient();
tsc.callBusinessLayer(o); // here im getting the exception
Debug.Print(""+signInEmail);
}
Client Side Web.Config
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<appSettings>
<add key="ValidationSettings:UnobtrusiveValidationMode" value="None" />
</appSettings>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ITestServ" />
<binding name="BasicHttpBinding_ITestServ1" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/Publish/TestServ.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_ITestServ" contract="ServiceReference.ITestServ"
name="BasicHttpBinding_ITestServ" />
<endpoint address="http://localhost/Publish/TestServ.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_ITestServ1" contract="TestRef.ITestServ"
name="BasicHttpBinding_ITestServ1" />
</client>
</system.serviceModel>
</configuration>
I know that this question has been asked to death, yet the answer remains elusive. I've been through numerous posts with suggested solutions but this error continues to plague me. Any help would be greatly appreciated.
I have a .Net 4.5 WCF service hosted on IIS which is consumed by an MVC5 web site on another IIS box. Communication works fine for the most part, but I need to allow the web site to upload files to the WCF service and the calls are all bombing out with the following error:
An unexpected error occurred: The remote server returned an unexpected response: (413) Request Entity Too Large
The methods being called in the web service take a single POCO as a parameter. The POCO contains a number of properties including a byte array for the contents of the file being uploaded. For example:
public class ProofOfAddressRequest : RequestBase
{
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string Region { get; set; }
public string City { get; set; }
public string PostCode { get; set; }
public string Country { get; set; }
public string FileName { get; set; }
public byte[] FileBytes { get; set; }
}
public ProofOfAddressResponse SubmitProofOfAddress(ProofOfAddressRequest data)
{
// TODO... Save the record
}
The web site's web.config is currently as follows:
<configuration>
<configSections/>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IUserService" maxBufferPoolSize="2097152" maxBufferSize="2097152" maxReceivedMessageSize="2097152">
<readerQuotas maxDepth="32" maxStringContentLength="2097152" maxArrayLength="2097152" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<security mode="None"/>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:58354/Services/UserService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IUserService"
contract="UserService.IUserService" name="BasicHttpBinding_IUserService" />
</client>
</system.serviceModel>
<system.web>
<customErrors mode="Off" />
<authentication mode="None" />
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" maxRequestLength="4096"/>
</system.web>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
And the web service's web.config is:
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" maxRequestLength="4096"/>
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding" maxBufferPoolSize="2097152" maxBufferSize="2097152" maxReceivedMessageSize="2097152">
<readerQuotas maxDepth="32" maxStringContentLength="2097152" maxArrayLength="2097152" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<security mode="None"/>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceWithMetadata">
<!-- 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="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpBinding" scheme="http" />
<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>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="v11.0" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>
What I would like is to understand HOW to configure my config file(s) to allow a maximum upload size of say 2MB. If it is possible to pass the data in binary format rather than Base64 (or whatever) that would also be advantageous to decrease the bandwidth requirements between servers.
Communication between sites is currently over HTTP in my dev environment, but I'll also need to configure for HTTPS for test/production. Bonus points for pointers on the additional config.
Thanks in advance for any help you can provide on this. It's cost me a fair amount of time already and I'm no closer to a solution.
Found my answer - I originally posted a link to it here, but one of the mods decided to delete the answer (thanks for that!), so I'll post the solution in its entirety instead:
In order to allow payloads (such as files or large arrays of data) OVER the default of 40KB to be sent to a WCF Service method, the changes required are predominantly in the web.config file of the WCF project. There is also one minor tweak required in the client's configuration, so we'll look at that first:
<configuration>
...
<system.serviceModel>
<bindings>
<basicHttpBinding>
<!-- Large Message Upload (Begin) -->
<binding name="BasicHttpBinding_IUserService" maxBufferPoolSize="2097152" maxReceivedMessageSize="2097152" />
<!-- Large Message Upload (End) -->
<binding name="BasicHttpBinding_ISystemService" />
...
</basicHttpBinding>
</bindings>
...
</system.serviceModel>
</configuration>
When you first add a service reference to your client's project, Visual Studio automatically creates default binding and endpoint nodes in your config file. You'll need to add two new attributes to the binding node for your service: maxBufferPoolSize and maxReceivedMessageSize. Both attributes should have their values set to your desired file upload size limit IN BYTES. You'll also need to take note of the name for the next bit.
That's if for the client configuration, so on to the WCF Service. Here's an extract from mine:
<configuration>
...
<system.serviceModel>
<bindings>
<basicHttpBinding>
<!-- Large Message Upload (Begin) -->
<binding name="BasicHttpBinding_IUserService"
maxBufferSize="2097152"
maxBufferPoolSize="2097152"
maxReceivedMessageSize="2097152"
closeTimeout="00:50:00"
openTimeout="00:50:00"
sendTimeout="00:50:00"
receiveTimeout="00:50:00">
<readerQuotas maxDepth="32" maxStringContentLength="100000"
maxArrayLength="2097152" maxBytesPerRead="4096"
maxNameTableCharCount="16384" />
<security mode="None" />
</binding>
<!-- Large Message Upload (End) -->
</basicHttpBinding>
</bindings>
<services>
<!-- Large Message Upload (Begin) -->
<service name="BlexEngine.Services.UserService"
behaviorConfiguration="ServiceWithMetadata">
<endpoint name="Default"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IUserService"
contract="BlexEngine.Services.IUserService" />
</service>
<!-- Large Message Upload (End) -->
</services>
<behaviors>
<serviceBehaviors>
<!-- Large Message Upload (Begin) -->
<behavior name="ServiceWithMetadata">
<!-- Large Message Upload (End) -->
<!-- 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="true" />
</behavior>
</serviceBehaviors>
</behaviors>
...
</system.serviceModel>
...
</configuration>
As you can see there are three changes required:
1) Create a binding specifically for the service that you want to enable large file uploads for (my project publishes five services at the moment, but only one requires a larger file upload limit). Ensure that the value of the name attribute matches the name of the binding we noted in the client's web.config file. Copy the attributes and child nodes from the example above and modify as you see fit. All size values are, AKAIK, in bytes.
2) Jumping around a bit, we're going to move to the last change in the config extract next. Visual Studio creates a default behaviour node with all the correct settings, but does NOT set a name on that node, so add a name attribute and give it a value. ServiceWithMetadata was the value in the example I found, so that's what I used - I don't know if it really matters what you call it.
3) Create a service node for your service. The name must be the fully qualified name of your service class and the behaviourConfiguration needs to be the name of the service node, as set in step 2). Within the service node you'll need to configure an endpoint, the bindingConfiguration of which needs to be set to the name of the binding setup in step 1) and the contract of which needs to be set to the fully qualified name of the interface your service class adheres to.
That's it really. Figuring this out has taken far too long and I can't believe how complex the process has been or how little documentation there appears to be out there on this topic. To anyone suffering the same issue as I did: good luck! I hope that this post saves you the time I had to invest figuring this out the hard way.
Car.cs
[DataContract]
public class Car
{
[DataMember]
public string Id { get; set; }
[DataMember]
public Bitmap Image { get; set; }
}
ICarService.cs
[ServiceContract]
public interface ICarService
{
[OperationContract]
[WebGet(UriTemplate = "Car/{id}")]
Car GetCarId(string id);
}
CarService.svc.cs
public class CarService : ICarService
{
public Car GetCarId(string id)
{
var newCar = new Car
{
Id = id,
Image = new Bitmap("../../Atish.jpg")
};
return newCar;
}
}
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>
<services>
<service name="CarHaat.CarService">
<endpoint address="" behaviorConfiguration="restfulBehavior"
binding="webHttpBinding" bindingConfiguration="" contract="CarHaat.ICarService" />
<host>
<baseAddresses>
<add baseAddress="http://localhost/bookservice" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="restfulBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<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>
Problem is .... when i hit this url localhost:4765/CarService.svc/car/1 in browser, I get following exception. How can i resolve it?? I want to return an image in json format.
what is the call stack trace? if I were you, I would go to the debug > Exception menu and then tick the "thrown" check box for the Common Language Runtime Exceptions item. This will then take you to exactly where the exception is being thrown from. To me, I believe it could be thrown from the Bitmap constructor as you are giving it an incorrect path. you need to map the path to the image file in question by using Server.MapPath for example. It needs a fully qualified path to the file in question when it comes to the web platform.
in addition to that, the file will be locked until you dispose of the bitmap object so you may have issues. The best thing to do is probably return the byte[] of the image file to the client and let the client side deal with streaming it to the page (for example using the response to write the bytes to the page). it also makes sense if you are using the WCF platform and making a form of an API system, where you are not tied to using the .NET BCL's but to make it as generic as possible that majority of not all of the clients understand the native types
Return the image Serialized in Base64 (string) and then in the client Deserialize it
Like this
//Serialize
var bytes = File.ReadAllBytes(#"bbbd996028159395cce9b63d717bf0ef.jpeg");
var base64 = Convert.ToBase64String(bytes);
//Deserialize
var nbytes = Convert.FromBase64String(base64);
File.WriteAllBytes(#"yayaya.jpeg", nbytes);