WCF handling CORS & Options VERB - wcf

I have a wcf service hosted on IIS.
Almost all the documents say that to enable cors, you should handle the OPTIONS VERB. (Pre-Flight Requests)
I have a method whose signatures are :
[OperationContract]
[FaultContract(typeof(ExceptionManager))]
[WebInvoke(Method = "POST",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.WrappedRequest,
UriTemplate = "PostLog")]
string PostLog(List<LoginEntry> LoginLog);
I have created an attribute deriving from IServiceBehavior & hooked up this Class to my service & handled BeforeSendReply method to add Acces Control methods as :
public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
var httpHeader = reply.Properties["httpResponse"] as HttpResponseMessageProperty;
httpHeader.Headers.Add("Access-Control-Allow-Origin", "*");
httpHeader.Headers.Add("Access-Control-Request-Method", "POST,GET,PUT,DELETE,OPTIONS");
httpHeader.Headers.Add("Access-Control-Allow-Headers", "X-Requested-With,Content-Type");
}
This did not help me when i created a testcall in firefox. So i took it out from here & added this in Global.asax file as
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
HttpContext.Current.Response.Cache.SetNoStore();
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}
I could see in firefox 403 Error & my headers not being present.
so i went ahead & put those headers in IIS settings (Custom headers Tab). (I took the risk of sending those in each response).
Now i can see those headers in response in firefox, but I am still getting 403 Error.
This is the response header :
HTTP/1.1 403 Forbidden
Connection: Keep-Alive
Content-Length: 1758
Date: Thu, 05 Mar 2015 14:47:25 GMT
Content-Type: text/html
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization, Accept
I also tried Changing to Method="*" in WebInvoke. but still could not get it to work.
Thanks in Advance..

So finally Got it to Work.
This post helped me out.
enabling cross-origin resource sharing on IIS7
Turns out that the problem was in IIS 6 Site settings.
Solved it by the following steps :
In IIS, Select Site -> RightClick (Properties) ->
Under the Directory Tab Select Configuration Button.
Under the Mappings Tab. Search for Extension (.svc)
Click on Edit. Search for Label "Limit Verbs To".
Previous Value was "GET,HEAD,POST,DEBUG"
Replaced It With "GET,HEAD,POST,DEBUG,OPTIONS"
Also, I removed all those headers configs from IIS (coz I was already managing them Global.asax).

Related

AngularJS : Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource

here is my code :
angular.module('option')
.factory('optionListService', ['$resource', function($resource) {
return $resource(HOST+'option/action/:id', {}, {
'get': {method:'GET'},
'save': {method:'POST'},
'query': {method:'GET', isArray:true},
'remove': {method:'DELETE'},
'delete': {method:'DELETE'}
});
}]);
and this work for GET requests and not for POST !
I'm using Apache as a server and configured it with :
<Limit GET HEAD POST PUT DELETE OPTIONS>
Order Allow,Deny
Allow from all
</Limit>
Header set Access-Control-Allow-Origin "*"
and in my angularjs I include in config of module app:
delete $httpProvider.defaults.headers.common['X-Requested-With'];
delete $httpProvider.defaults.headers.post['Content-type'];
but the request POST still not working !!
I hope that someone can give any idea.
Add those headers on the server side:
Access-Control-Request-Headers: X-Requested-With, accept, content-type
Access-Control-Allow-Methods: GET, POST
If still not working post the details of the preflight OPTIONS request which the browser is sending.
Why is this required?
If it is not a simple request (e.g. GET or POST of form data) the browser sends a preflight HTTP OPTIONSrequest to the server to check if CORS is allowed. This request contains some Access-Control-Request headers (can differ based on the specific request):
Access-Control-Request-Headers: accept, content-type
Access-Control-Request-Method: POST
Now it is important that the server references the same Access-Control-Allow header in the response:
Access-Control-Allow-Headers: accept, content-type
Access-Control-Allow-Methods: POST
Access-Control-Allow-Origin: *
Otherwise the request is rejected by the browser.
#ilyas : finaly after 3hours of reseach I sovelved this problem
//Part added by ilyas :
if (isset($_SERVER['HTTP_ORIGIN'])) {
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Max-Age: 86400'); // cache for 1 day
}
//End of part.
I hope this help others.
Add Header into your file which you hitting from ajax call as follows
<? php header('Access-Control-Allow-Origin: *'); ?>
I found great example and explanation here http://www.codingpedia.org/ama/how-to-add-cors-support-on-the-server-side-in-java-with-jersey/
#GET
#Path("{id}")
#Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response getPodcastById(#PathParam("id") Long id, #QueryParam("detailed") boolean detailed)
throws IOException, AppException {
Podcast podcastById = podcastService.getPodcastById(id);
return Response.ok() //200
.entity(podcastById, detailed ? new Annotation[] {PodcastDetailedView.Factory.get()} : new Annotation[0])
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT")
.allow("OPTIONS").build();
}
Here is a problem on server side. If your application is using spring framework. You can fix it by using the filter method
#Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws ServletException, IOException {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
res.setHeader("Access-Control-Max-Age", "3600");
res.setHeader("Access-Control-Allow-Headers", "X-PINGOTHER,Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization");
res.addHeader("Access-Control-Expose-Headers", "xsrf-token");
if ("OPTIONS".equals(req.getMethod())) {
res.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
By the way, you can dig deeper it via post angularjs spring cross-origin request blocked

WCF POST service with WebInvokeBodyStyle as wrapped not working as expected

I have created a WCF POST service with below mentioned signature. This is hosted successfully in IIS and I can see it in the service's help page as:
[OperationContract]
[WebInvoke(BodyStyle = WebMessageBodyStyle.Wrapped,
RequestFormat = WebMessageFormat.Xml,
ResponseFormat = WebMessageFormat.Xml,
Method = "POST",
UriTemplate = "TestMethod/{lang}/{str}/{selectedstring}/")]
string TestMethod(string lang, string str, string selectedstring, string mylist, int testval);
On the service's help page the method shows correctly as
TestMethod/{lang}/{str}/{selectedstring}/ || POST || Service at http://localhost:86/MyRestService.svc/TestMethod/{LANG}/{STR}/{SELECTEDSTRING}/
I am trying to call this service using fiddler with below mentioned options (Based on a few look up on blogs):
Method: Post
URL - 'http://servername:86/MyRestService.svc/TestMethod/en-us/str1/qad11/'
Req. Headers:
User-Agent: Fiddler
Host: servername:86
Content-Type: application/xml
Request Body:
<TestMethod xmlns="http://tempuri.org/"><mylist>string val</mylist><testval>3</testval></TestMethod>
However it always gives me an HTTP result code 411 (Length Required), the same error when I try to call the service from my .net test stub.
Fiddler should calculate the HTTP header named Content-Length for you (at least it does for v2.3.9.3) Check in the raw tab of the request for something like: Content-Length: nnn where nnn is the string length of the request body. If not, then you'll need to add it yourself. Also, you could try a browser plug-in like the POSTMan chrome plug to create your requests.

Restful WCF service POST methods returns HTTP400 error in fiddler2

have created simple Restful service for log in verification. Following are my interface and class definitions.
Interface IDemo:
public interface IDemo
{
[OperationContract]
[WebInvoke(RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "/ValidateUser?Username={UserName}&Password={Password}",
Method = "POST")]
string ValidateUser(string Username, string Password);
}
Class Demo :
public class Demo:IDemo
{
public string ValidateUser(string Username, string Password)
{
Users objUser = new Users();
objUser.UserID = Username;
objUser.Password = Password;
string Msg = LoginDataService.ValidateUser(Username, Password);
return Msg;
}
}
localhost:49922/Demo.svc/ValidateUser?Username=demo&Password=demo (with http:\)
When I try to parse the above URL under the Post Method in Fiddler2 I got Bad Request HTTP400 error.
Can anyone help me what is wrong in my code.
Thanks & Regards,
Vijay
Your URI template looks like you are sending the parameters in the URL. But when you use POST the parameters are sent in the http body.
Note you should not send the username and passord in the url as it can be logged.
For the above REST method the POST from Fiddler needs to be as shown below:
POST http://localhost/Sample/Sample.svc/ValidateUser?Username=demo&Password=demo HTTP/1.1
User-Agent: Fiddler
Content-Type: application/json
Host: rajeshwin7
Content-Length: 0
Doing so i get back a 200 OK HTTP Status as shown below:
HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 44
Content-Type: application/json; charset=utf-8
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 14 Jun 2012 15:35:28 GMT
"Server returns username demo with password demo"

Internet Explorer error using Asp MVC 4.0 FileResult

I have the following code, deployed on a https Asp site, build with MVC 4.0:
public FileResult ANotSoWorkingFunction(string filePath, string fileName)
{
pathToFile = string.Format("~/{0}/{1}", pathToFile, fileName);
return File(new FileStream(pathToFile, FileMode.Open), "application/pdf", fileName);
}
This will work (as you many of you probably already guessed) with Chrome, Firefox and IE9. But it will throw a:
---------------------------
Windows Internet Explorer
---------------------------
Internet Explorer cannot download someFileName from a_site.com.
Internet Explorer was not able to open this Internet site. The requested site is either unavailable or cannot be found. Please try again later.
---------------------------
OK
---------------------------
On IE6,7,8
Any ideas or clues on this one are greatly appreciated as I already spend the hole day playing with html header.
EDIT:
Here are the header from IE7:
HTTP/1.1 200 OK
Cache-Control: private, no-cache="Set-Cookie"
Content-Type: application/pdf
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 4.0
X-AspNet-Version: 4.0.30319
Set-Cookie: .ASPXAUTH=; expires=Mon, 11-Oct-1999 21:00:00 GMT; path=/; HttpOnly
X-Powered-By: ASP.NET
Date: Wed, 04 Apr 2012 08:43:50 GMT
Content-Length: 233324
And here are the ones from IE9:
HTTP/1.1 200 OK
Cache-Control: private, no-cache="Set-Cookie"
Content-Type: application/pdf
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 4.0
X-AspNet-Version: 4.0.30319
Set-Cookie: .ASPXAUTH=; expires=Mon, 11-Oct-1999 21:00:00 GMT; path=/; HttpOnly
X-Powered-By: ASP.NET
Date: Wed, 04 Apr 2012 08:42:14 GMT
Content-Length: 233324
Thank you,
I think I also ran into your problem.
I am also running IIS 7.5 and downloading a PDF through an action on an HTTPS request. For reasons I have yet to isolate, IIS 7.5 seems to be appending no-cache="Set-Cookie" to my Cache-Control response header regardless of what I set the Cache settings to on the Response. This was causing the fairly well documented no-cache issue on IE6, IE7, and IE8.
To resolve this, I made a small wrapper around the FileContentResult that cleared the headers, called the parent, then set the Cacheability to 'Private'. This side-stepped IIS 7.5's insistence to add no-cache="Set-Cookie" to the header, and the file downloaded properly in all browsers I tested. If you want to emulate what I did, first, here's my FileContentResult wrapper.
public class PdfContentResult : FileContentResult {
public PdfContentResult(byte[] data) : base(data, "application/pdf") { }
public PdfContentResult(byte[] data, string fileName) : this(data) {
if (fileName == null) {
throw new ArgumentNullException("fileName");
}
this.FileDownloadName = fileName;
}
public override void ExecuteResult(ControllerContext context) {
context.HttpContext.Response.ClearHeaders();
base.ExecuteResult(context);
context.HttpContext.Response.Cache.SetCacheability(HttpCacheability.Private);
}
}
Then I added an extension method to my ControllerExtensions so that it would be simple to find:
public static class ControllerExtensions {
public static PdfContentResult Pdf(this Controller controller, byte[] fileContents, string fileName) {
return new PdfContentResult(fileContents, fileName);
}
}
Finally, within the Action, I did the equivalent of this:
public ActionResult MyGeneratedPdf() {
byte[] myPdfContentInByteStream = GetPdfFromModel();
return this.Pdf(myPdfContentInByteStream, "MyFile.pdf");
}
Obviously, if you're downloading all kinds of data types, you might not want to bind the workaround so closely to PDF.
We resolved this by changing the cache-control header before streaming the file.
Simplified code sample:
var browserInformation = Request.Browser;
//Set as private if current browser type is IE
Response.AppendHeader("cache-control",
browserInformation.Browser == "IE" ? "private" : "no-cache");
return File(fileName, contentType, downloadFileName);
This worked (yay).. BUT I was left with a lack of clarity on why we had to do it this way for that specific site. We have four websites running on the same box, all under SSL, and only one had this header problem. I compared the web.config files and looked at the setup in IIS but couldn't shed any further light on why that one site needs those headers set explicitly.
If anyone has more to add on the above (for added clairty) that would be great.
In older versions of IE if a user tries to download a file over a HTTPS connection, any response headers that prevent caching will cause the file download process to fail. Below are most common headers which are causing the issue:
Cache-Control with the values no-cache or no-store
Vary with any value
Pragma with value no-cache
You can create an ActionFilterAttribute which will clear cache headers for you like this:
public class ClearCacheHeadersAttribute : FilterAttribute, IActionFilter
{
public void OnActionExecuted(ActionExecutedContext filterContext)
{
return;
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContext.Current.Response.Headers.Remove("Cache-Control");
HttpContext.Current.Response.Headers.Remove("Vary");
HttpContext.Current.Response.Headers.Remove("Pragma");
//Set the cache headers any way you like keeping in mind which values can brake the download
}
}
And decorate yoour action with it:
[ClearCacheHeaders]
public FileResult ANotSoWorkingFunction(string filePath, string fileName)
{
pathToFile = string.Format("~/{0}/{1}", pathToFile, fileName);
return File(new FileStream(pathToFile, FileMode.Open), "application/pdf", fileName);
}

WCF REST: specify content-type on WebGet Attribute doesn't seem to be working

probably something i doing wrong, but i am returning XML from my WCF Rest service which is built with VS 2010. In fiddler you can see here that it returns test/html as the content-type
HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 222
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Mon, 16 Aug 2010 20:49:55 GMT
So i went ahead and added the following on the webget attribute on my method but it still returns text/html ... I presume that i should return the content type of text/xml because i am in fact returning XML?
Heres my method, i added the ResponseFormat to the attribute... I wasn't sure if i needed bodystyle (i have no idea what it does but saw it in an example :-) )
[WebGet(UriTemplate = "", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Xml)]
public List<SampleItem> GetCollection()
{
// TODO: Replace the current implementation to return a collection of SampleItem instances
return new List<SampleItem>() { new SampleItem() { Id = 1, StringValue = "Hello" } };
}
anyway after the change and rebuilding of the project it still returns the wrong content type ... am i missign somthing?
HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 222
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Mon, 16 Aug 2010 20:54:15 GMT
EDIT
Ok i got a working solution but the attribute method has NO EFFECT, very strange...but if i put this
WebOperationContext.Current.OutgoingResponse.ContentType = "text/xml";
Now i check fiddler and the content-type is actually text/xml.
But i need to put this in every method and the attribute method seems to have no effect.
Anybody know why?
According to this the Firefox request headers has a higher priority for text/html than text/xml, resulting in WCF service methods decorated with xml or json returning with the "wrong" response, although I can imagine it is the correct behavior.
You can force a response content type by explicitly setting
WebOperationContext.Current.OutgoingResponse.ContentType = "text/xml";
or equivalent. I guess this is the only alternative if you truly want to force a specific content type response for all browsers/clients.
See e.g.
WCF ResponseFormat For WebGet
I think you want e.g.
OutgoingWebResponseContext context =
WebOperationContext.Current.OutgoingResponse;
context.ContentType = "image/jpeg";
ResponseFormat controls something else.
Old post, but here is what I found on MSDN's Blog Getting Started with WCF WebHttp Services in .NET 4:
Your project has to use the Full .NET 4 Framework, not the Client Profile.
Once I did that, and restarted the project, I was able to add System.ServiceModel.Web from the list of References.
I hope this helps someone.