Calling WCF Services with jQuery - javascript

I have 2 projects from which I need to call WCF services.
I have a problem calling services from one of them.
Therefore I made a simple service which is identical in both projects called Test1.
The SVC, ISVC and the Web.Config files are identical.
Any ideas what else can influance and be the reason why one project is working file and the other return a Bad request error.
I am working with Visual studio 2012.
Following is my code:
SVC file:
namespace Proj1.Web
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Proj1SVC : IProj1SVC
{
public string Test1()
{
return "Project 1";
}
}
}
ISVC file:
namespace Proj1.Web
{
[ServiceContract]
public interface IProj1SVC
{
[OperationContract]
string Test1();
}
}
Web.Config file:
<?xml version="1.0"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<connectionStrings>
<add name="Proj1dbConnectionString" connectionString="Data Source=Proj1Comp\SQLEXPRESS;Initial Catalog=Proj1dbKK;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<roleManager enabled="true"/>
<compilation debug="true" targetFramework="4.0">
</compilation>
<!--
The <authentication> section enables configuration
of the security authentication mode used by
ASP.NET to identify an incoming user.
-->
<!-- <authentication mode="Windows"/> -->
<authentication mode="Forms">
<!-- The name, protection, and path attributes must match
exactly in each Web.config file. -->
<forms loginUrl="login.aspx" name=".ASPXFORMSAUTH" protection="All" path="/" domain="kk.Proj1.com" timeout="600"/>
</authentication>
<!-- Validation and decryption keys must exactly match and cannot
be set to "AutoGenerate". The validation and decryption
algorithms must also be the same. -->
<machineKey validationKey="SomeValidationKeyInHex" decryptionKey="SomeDecryptionKeyInHex" validation="SAA1"/>
<authorization>
<allow roles="administrators"/>
<allow users="?" />
</authorization>
<!--
The <customErrors> section enables configuration
of what to do if/when an unhandled error occurs
during the execution of a request. Specifically,
it enables developers to configure html error pages
to be displayed in place of a error stack trace.
<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
<error statusCode="403" redirect="NoAccess.htm" />
<error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>
-->
<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID"/>
</system.web>
<!-- Added for server side authentication data to be available in the WCF service -->
<!-- STX -->
<system.web.extensions>
<scripting>
<webServices>
<authenticationService enabled="true" requireSSL="false"/>
</webServices>
</scripting>
</system.web.extensions>
<!-- ETX -->
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true"/>
<diagnostics>
<messageLogging
logEntireMessage="true"
logMalformedMessages="false"
logMessagesAtServiceLevel="true"
logMessagesAtTransportLevel="false"
maxMessagesToLog="3000"
maxSizeOfMessageToLog="2000"/>
</diagnostics>
</system.serviceModel>
</configuration>

you need to specify attributes at operation level in the service contract file for each method or operation. To do this, decorate the method with WebInvoke, which marks a service operation as one that responds to HTTP requests other than GET. Accordingly, your operational level code in the contract file will be as follows:
[OperationContract]
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.Wrapped,
ResponseFormat = WebMessageFormat.Json)]
string Test1(string Id);
You need to change the default configuration created by Visual Studio in Web.Config file for WCF services, so that it works with the HTTP protocol request send by jQuery client code.
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="EndpBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="ServiceBehavior" name="Service">
<endpoint address="" binding="webHttpBinding"
contract="IService" behaviorConfiguration="EndpBehavior"/>
</service>
</services>
</system.serviceModel>
Call ur service using jQuery.ajax()
function CallService() {
$.ajax({
type: Type, //GET or POST or PUT or DELETE verb
url: Url, // Location of the service
data: Data, //Data sent to server
contentType: ContentType, // content type sent to server
dataType: DataType, //Expected data format from server
processdata: ProcessData, //True or False
success: function(msg) {//On Successfull service call
ServiceSucceeded(msg);
},
error: ServiceFailed// When Service call fails
});
}
function ServiceFailed(result) {
alert('Service call failed: ' + result.status + '' + result.statusText);
Type = null;
varUrl = null;
Data = null;
ContentType = null;
DataType = null;
ProcessData = null;
}

Related

Return individual error message after an ajax call in ASP.NET MVC 5

When I send an ajax request to the server, I want to return an individual message to the client in the responseText in case of an error. In debug mode on my development machine this works fine. Unfortunately, in production mode on the web server I always get an error message "Bad Request" but no longer the individual message. I am developing my application in ASP.NET MVC 5 and I am using jQuery 3.6.0.
My ajax request looks like this:
$.ajax({
type: 'POST',
url: 'myURL',
data: {
val1: clientVal1,
val2: clientVal2
},
success: function (res) {
//do smthg...
},
error: function (response) {
alert(response.responseText);
}
});
On the server side, I take the ajax call like this:
[HttpPost]
public ActionResult myURL(string val1, string val2)
{
if(val1.contains(val2))
{
}
else
{
Response.StatusCode = 400;
Response.Write("My custom error msg.");
return new HttpStatusCodeResult(400);
}
return Json(new { someVal1, otherVal2}, JsonRequestBehavior.AllowGet);
}
The httperrors in my webconfig file look like this:
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" subStatusCode="-1" />
<remove statusCode="403" subStatusCode="-1" />
<remove statusCode="500" subStatusCode="-1" />
<error statusCode="404" path="/ErrorHandling/http404" responseMode="ExecuteURL" />
<error statusCode="403" path="/ErrorHandling/http403" responseMode="ExecuteURL" />
<error statusCode="500" path="/ErrorHandling/http500" responseMode="ExecuteURL" />
</httpErrors>
What am I doing wrong?
I have found the solution. First I had to move the redirection to the individual error pages in the web.config to the <system.web> area. Now my system.web area looks like this ([...] means that there are other settings which are not relevant for this):
<system.web>
[...]
<customErrors mode="On" redirectMode="ResponseRedirect" defaultRedirect="/ErrorHandling/http500">
<error statusCode="404" redirect="/ErrorHandling/http404" />
<error statusCode="403" redirect="/ErrorHandling/http403" />
<error statusCode="500" redirect="/ErrorHandling/http500" />
</customErrors>
[...]
</system.web>
After that, I had to change the system.webServer section as suggested in the post by freedomn-m and suggested by Rahul Sharam as follows:
<httpErrors errorMode="Custom" existingResponse="PassThrough">
</httpErrors>
Now everything works as it should.

post of Uint8Array from angular javascript to wcf service is null when reaching service

Hi I'm trying to post a Uint8Array from angular javascript client to wcf service. The problem is that when
the array arrives at the service it is null. On the client end I've tried changing the array to different
types (int8, int16 etc..) and also not stringifying the data, but in all cases when it arrives at the
service it is null. On the service side I've tried to change the BodyStyle of the interface
from Wrapped to Bare, but got a 500 error. I've also made changes to web config parameters,
but I think web config is ok, because the post is actually making it to the method.
Any ideas what could be the problem? ultimately I'm trying to post an image from webcam on ipad or laptop
to wcf service for input into sql server. My code is below
Thanks
Pete
//ANGULAR post to WCF
const data = new Uint8Array(8);
data[0] = 26;
let body:any = JSON.stringify(data);// body = '{"0":26,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0}'
let headers = {'Access-Control-Allow-Credentials':'false',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'DELETE, POST, GET, OPTIONS, PUT',
'Access-Control-Allow-Headers': 'application/json',
'Content-Type':'application/json'}
this.http.post(GlobalConstants.UploadServiceURL + "UploadPhotoDB", body, {'headers':headers}).subscribe(data => {
console.log(data);// null
})
WCF SERVICE
//Method
public byte[] UploadPhotoDB(byte[] input){//input is null
return input;
}
//Interface
[OperationContract(Name = "UploadPhotoDB")]
[DataContractFormat]
[WebInvoke(Method = "POST",
UriTemplate = "UploadPhotoDB/",
BodyStyle = WebMessageBodyStyle.Wrapped,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json
),
]
byte[] UploadPhotoDB(byte[] input);
//Applicable parts of WebConfig
<service name="SARIService.ServiceUpload" behaviorConfiguration="ServiceBehavior">
<endpoint address=""
binding="webHttpBinding"
bindingConfiguration="webHttpBindingConfig"
contract="SARIService.IServiceUpload"
behaviorConfiguration="web">
</endpoint>
</service>
<endpointBehaviors>
<behavior name="web">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<bindings>
<webHttpBinding>
<binding
maxBufferSize="999999" maxReceivedMessageSize="999999" />
<binding name="webHttpBindingConfig"
maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" transferMode="Streamed" sendTimeout="00:05:00">
<!-- <security mode="Transport"/>-->
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
</binding>
</webHttpBinding>
</bindings>
On the angular javascript side I'm using ngx-webcam module to get the image. This has an imageAsBase64 property which stores the image as a base64 string. When I posted this string to the service and used FromBase64String on the c# wcf service to convert back to a byte array it worked.

XMLHttpRequest post 400 Bad request error when calling wcf Service

Hi I'm posting to a wcf service from javascript. I can post a single parameter (string, blob, int) fine, but when I try to put the data in a class I get a 400 Bad Request error. I've tried both Bare and Wrapped for my BodyStyle, but get the same error for each. Any ideas what could be happening?
Thanks
Pete
C# Data Contract:
[DataContract]
public class TestData
{
[DataMember]
public string SubmissionID { get; set; }
}
C# Interface:
[OperationContract(Name = "Upload")]
[DataContractFormat]
[WebInvoke(Method = "POST",
UriTemplate = "Upload/",
BodyStyle = WebMessageBodyStyle.Wrapped,//Bare gives same error
ResponseFormat = WebMessageFormat.Json)]
String Upload(TestData ps);
C# Service Method:
public String Upload(TestData ps)
{
....
return "Submission Complete";
}
Javascript call:
var TestData = {SubmissionID: "1" };
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost:59070/WCFUploader.svc/Upload/', true);
xhr.send(TestData);//400 Bad Request
C# Web Config:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.6.1" />
<httpRuntime targetFramework="4.6.1"/>
</system.web>
<system.serviceModel>
<services>
<service name="PhotoUploadServiceTest.WCFUploader" behaviorConfiguration="defaultServiceBehavior">
<endpoint address="" binding="webHttpBinding" behaviorConfiguration="defaultEndpointBehavior"
contract="PhotoUploadServiceTest.IWCFUploader" />
</service>
</services>
<bindings>
<webHttpBinding>
<binding maxBufferSize="2147483647"
maxBufferPoolSize="2147483647"
maxReceivedMessageSize="2147483647"
transferMode="Streamed"
sendTimeout="00:05:00">
<readerQuotas maxDepth="2147483647"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647"/>
<security mode="None" />
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="defaultEndpointBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="defaultServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</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>
The problem was in my javascript call. I needed to set the content of the request header to "application/json" and needed to create a String serial of the object before I sent it -- used dojo.toJson from the dojo library:
var TestData = {SubmissionID: "1" };
xhr.setRequestHeader("Content-type", "application/json");
var xhr = new XMLHttpRequest();
xhr.open('POST',
'http://localhost:59070/WCFUploader.svc/Upload/', true);
xhr.send(dojo.toJson(TestData));//this worked!!

access wcf self service host using js

I created a wcf self service host
I can access it , and see it's wsdl
but when trying to add the /js extension to the path I get 405 error.
I cannot understand why, while doing the same with a asp.net web applicaton it worked ok.
wcf class :
namespace A
{
[ServiceBehavior(IncludeExceptionDetailInFaults=true)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Hello : IHello
{
public string SayHi()
{
return "Hiush !";
}
}
}
wcf interface:
namespace A
{
[ServiceContract]
public interface IHello
{
[OperationContract]
string SayHi();
}
}
wcf svc file:
<%# ServiceHost Language="C#" Debug="true" Service="A.Hello" %>
the self service host:
namespace SelfServiceHost
{
class Program
{
static void Main(string[] args)
{
using (ServiceHost helloHost = new ServiceHost(typeof(A.Hello)))
{
helloHost.Open();
Console.WriteLine("HelloHost started # " + DateTime.Now);
Console.ReadKey();
}
}
}
}
self service host 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>
<bindings>
<basicHttpBinding>
<binding name="" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="true" hostNameComparisonMode="StrongWildcard"
maxBufferSize="524288" maxBufferPoolSize="524288" maxReceivedMessageSize="524288"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="524288" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<!--<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>-->
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="A.Hello">
<endpoint address="PINCalc" behaviorConfiguration="AAA"
binding="webHttpBinding" contract="A.IHello">
<!--<identity>
<dns value="localhost"/>
</identity>-->
</endpoint>
<host>
<baseAddresses>
<add baseAddress="http://localhost:3020/Hello.svc"/>
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="True"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="AAA">
<enableWebScript/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>

Sending image in base64 to Webservice - 'application/octet-stream' was not the expected type 'text/xml; charset=utf-8'

I'm trying to save an html5 canvas content, to localhost by using a webserver.
I'm getting the canvas value in base64 and I send it to my webservice.
But when I send the data to the webservice I get this error and the file is not saved:
415: "Cannot process the message because the content type
'application/octet-stream' was not the expected type 'text/xml;
charset=utf-8'."
What am I doing wrong?
Service.vb
Imports System.IO
Imports System.Drawing
Public Class Service
Implements IService
Public Sub New()
End Sub
Public Function savePictureBase64(bytes As Byte()) As Boolean Implements IService.savePictureBase64
Dim fullOutputPath As String = "c:\temp\file.png"
'get a temp image from bytes, instead of loading from disk
'data:image/gif;base64,
Dim imagem As Image
Using ms As New MemoryStream(bytes)
imagem = Image.FromStream(ms)
End Using
File.WriteAllBytes(fullOutputPath, (bytes))
Return True
End Function
End Class
IService.vb
<ServiceContract()>
Public Interface IService
<OperationContract()>
Function savePictureBase64(bytes As Byte()) As Boolean
' TODO: Add your service operations here
End Interface
Javascript
function save () {
var image = document.getElementById("sketchpad").toDataURL("image/png");
image = image.replace('data:image/png;base64,', '');
$.ajax({
type: 'POST',
url: 'http://localhost:52193/service.svc',
data: image,
contentType: 'application/octet-stream',
success: function (msg) {
alert('Image saved successfully !');
},
error: function(result) {
alert("Error");
}
});
}
</script>
web.config
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
</appSettings>
<system.web>
<compilation debug="true" strict="false" explicit="true" targetFramework="4.5"/>
<httpRuntime targetFramework="4.5"/>
<pages>
<namespaces>
<add namespace="System.Runtime.Serialization"/>
<add namespace="System.ServiceModel"/>
<add namespace="System.ServiceModel.Web"/>
</namespaces>
</pages>
</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>
<bindings>
<basicHttpBinding>
<binding messageEncoding="Mtom">
</binding>
</basicHttpBinding>
</bindings>
<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>
The error is the call that you made by Javascript code. You try to send a string, the webservice expected an XML message:
expected type 'text/xml; charset=utf-8'.
I don't know how complicated it is to compose a webservice XML message from Javascript, but I think that you can change your approach. Your service is hosted under IIS, can you build an HttpHandler?
public class UploadBase64 : IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
string image_string = string.Empty;
using (StreamReader sr = new StreamReader(context.Request.InputStream))
image_string = sr.ReadToEnd();
byte[] image_bin = Convert.FromBase64String(image_string);
File.WriteAllBytes(#"c:\temp_10\test01.png", image_bin);
}
}
...and add this to your web.config file:
<system.web>
<httpHandlers>
<add verb="POST" path="UploadBase64.aspx" type="WebApplication1.UploadBase64"/>
</httpHandlers>
</system.web>

Categories

Resources