Cross domain- post data from jQueryMobile to remote wcf service - wcf

I am using WCF service to get data and post data to database from my jQueryMobile application. Please note my service is in another server. I was able to get data from the remote service. But I am having issues in updating data using POST method. Below is my code, please help me to find the solution.
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title></title>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
<script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>
</head>
<body>
<div data-role="page" id="index">
<div data-role="content">
<input name="text-1" id="text1" value="" type="text">
<input name="text-2" id="text2" value="" type="text">
Update
</div>
<script type="text/javascript" charset="utf-8">
$(document).on('pagebeforeshow', '#index', function () {
$("#useJSONP").click(function () {
var id = $("#text1").val();
var name = $("#text2").val();
var userData = { "EmployeeID": id, "FirstName": name };
$.ajax({
url: "http://Mysite:83/FromDBDataService.svc/PostEmployeeData?callback=?",
type: "POST",
data: userData,
crossDomain: true,
contentType: "application/json; charset=utf-8",
dataType: "jsonp",
processdata: true,
success: function res(msg) {
alert("hello" + msg);
},
error: function error(response) {
alert("error");
}
});
});
});
</script>
</div>
</body>
</html>
WCF Service:-
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Data.SqlClient;
using System.Web.Configuration;
using System.Data;
using System.Reflection;
namespace ServiceSite
{
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class FromDBDataService
{
[OperationContract]
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.Wrapped,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
public void PostEmployeeData(int EmployeeID,string FirstName)
{
SqlConnection con = new SqlConnection(WebConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString);
SqlCommand cmd = new SqlCommand("update Employees set FirstName=#FirstName where EmployeeID=#EmployeeID", con);
SqlDataAdapter da = new SqlDataAdapter(cmd);
cmd.Parameters.Add(new SqlParameter("#EmployeeID", EmployeeID));
cmd.Parameters.Add(new SqlParameter("#FirstName", FirstName));
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
}
public class EmployeeNew
{
public int EmployeeID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
Thanks,
Bavya.

You will not be able to make cross domain POST requests. There are some hacks you might be interested in. Here another link
I would also suggest that you learn more about same origin policies.
JSONP request is executed by placing the script within <script></script> which you can't do for POST requests.

Related

Programmatically generating request verification token

Starting with an empty MVC project, here's my Startup.cs:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
namespace AntiForgeryExample
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseDeveloperExceptionPage();
app.UseStatusCodePages();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
}
}
And here's my HomeController.cs:
using Microsoft.AspNetCore.Mvc;
using System.Net;
namespace AntiForgeryExample
{
public class XyzController : Controller
{
[HttpPost]
[ValidateAntiForgeryToken]
public string Fgh() => "fgh 1";
[HttpGet]
public ContentResult Efg()
{
return new ContentResult()
{
ContentType = "text/html",
StatusCode = (int)HttpStatusCode.OK,
Content = #"<!DOCTYPE html>
<html>
<body>
<form method=""post"" action=""/Xyz/Fgh"">
<button type=""submit"">123</Button>
</form>
</body>
</html>"
};
}
}
}
The following line in Startup.cs adds the anti-forgery middleware:
services.AddMvc();
So, if we go to http://localhost:52838/Xyz/Efg, we get the simple page with a single button:
If we press the button, we get a 400 "Bad Request" response:
I'm assuming this is because we haven't passed a valid request verification token as part of the post. The Fgh method has the ValidateAntiForgeryToken attribute applied:
[HttpPost]
[ValidateAntiForgeryToken]
public string Fgh() => "fgh 1";
Thus a token is required when calling this method.
As described on this page, normally the code for this token will automatically be included if you use the form tag helper with ASP.NET Core MVC or a Razor Page. It will look something like this and be included as part of the form tag:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
In the example program I show above, we're programmatically generating the HTML with the form.
My question is, is there a way to programmatically generate the required token from C#, without having to go through using an MVC view or Razor Page. The idea would be that we'd get the token value and then include the input tag:
<input name="__RequestVerificationToken" type="hidden" value="TOKEN VALUE HERE">
I shared this question on the /r/dotnet subreddit.
/u/kenos1 provided a very helpful answer there:
You can inject Microsoft.AspNetCore.Antiforgery.IAntiforgery and call GetTokens() on it.
Here’s the documentation: link
As he mentions there, we inject IAntiforgery at the XyzController constructor:
private IAntiforgery antiforgery;
public XyzController(IAntiforgery antiforgery_)
{
antiforgery = antiforgery_;
}
We call GetAndStoreTokens on the IAntiforgery instance that we injected:
var token_set = antiforgery.GetAndStoreTokens(HttpContext);
And finally, we use the resulting token in the generated HTML:
return new ContentResult()
{
ContentType = "text/html",
StatusCode = (int)HttpStatusCode.OK,
Content = string.Format(#"<!DOCTYPE html>
<html>
<body>
<form method=""post"" action=""/Xyz/Fgh"">
<button type=""submit"">123</Button>
<input name=""__RequestVerificationToken"" type=""hidden"" value=""{0}"">
</form>
</body>
</html>",
token_set.RequestToken)
};
Here is the controller file in its entirety:
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using System.Net;
namespace AntiForgeryExample
{
public class XyzController : Controller
{
private IAntiforgery antiforgery;
public XyzController(IAntiforgery antiforgery_)
{
antiforgery = antiforgery_;
}
[HttpPost]
[ValidateAntiForgeryToken]
public string Fgh() => "fgh 1";
[HttpGet]
public ContentResult Efg()
{
var token_set = antiforgery.GetAndStoreTokens(HttpContext);
return new ContentResult()
{
ContentType = "text/html",
StatusCode = (int)HttpStatusCode.OK,
Content = string.Format(#"<!DOCTYPE html>
<html>
<body>
<form method=""post"" action=""/Xyz/Fgh"">
<button type=""submit"">123</Button>
<input name=""__RequestVerificationToken"" type=""hidden"" value=""{0}"">
</form>
</body>
</html>",
token_set.RequestToken)
};
}
}
}
The official ASP.NET Core 3.1 documentation mentions the GetAndStoreTokens method here.

MVC Web App Error HTTP 404

Im doing an MVC tutorial and Im in the part of doing a really basic web app.
This is the Controller inside my Controller folder:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace FirstMVCApplication.Controllers
{
public class HomeContoller : Controller
{
//
// GET: /HomeContoller/
public ActionResult Index()
{
int hour = DateTime.Now.Hour;
ViewBag.Greeting =
hour < 12
? "Good Morning. Time is" + DateTime.Now.ToShortTimeString()
: "Good Afternoon. Time is " + DateTime.Now.ToShortTimeString();
return View();
}
}
}
And this is my View inside View Folder:
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
#ViewBag.Greeting (<b>From Index View</b>)
</div>
</body>
</html>
Im using Razor.
And when I execute it It returns an HTTP 404 resource not found. It is an Empty Web MVC-4 Application.
EDIT
RouteConfig
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace FirstMVCApplication
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
}
Delete this #{ Layout = null; } from the Layout.cshtml file you posted here
Add #RenderBody() to Layout.cshtml file you posted here
In the Index.cshtml file which you do have here. Add at the top of the page file
#{ Layout = "~/Views/Shared/Layout.cshtml"; }

DropDownListFor issue with selected values

I'm fairly new (okay well very new) to MVC. I'm trying to create a cascading dropdown list, where I can also preselect a value.
I've spent most of the day on this, but not really got very far. I've looked at a lot of resources, though the most useful were:
http://www.deliveron.com/blog/post/Creating-a-Cascading-Dropdown-in-ASPnet-MVC-3-and-jQuery.aspx - I used this heavily and got my own version of it working, I couldn't get there example working.
http://odetocode.com/blogs/scott/archive/2013/03/11/dropdownlistfor-with-asp-net-mvc.aspx - general oversite.
MVC DropDownList SelectedValue not displaying correctly - There is what appears to be a really good example here, following the view-model method, but for some reason it didn't seem to work for me.
What I've got so far is:
Model:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace BLPrototype.Models
{
public class VehicleModels
{
public List<vehicle_make> getVehicleMakeList()
{
using (var db = new BLEntities())
{
List<vehicle_make> vmk = db.vehicle_make.OrderBy(r => r.vmk_name).ToList();
return vmk;
}
}
public List<vehicle_group> getVehicleModelList(string vmk_id)
{
using (var db = new BLEntities())
{
List<vehicle_group> vmo = db.vehicle_group.Where(v => v.vg_vmk_id == vmk_id).OrderBy(r => r.vg_name).ToList();
return vmo;
}
}
}
public class vmCatalogue1
{
public string Title { get; set; }
[Display(Name = "Select a make")]
public IEnumerable<SelectListItem> selectVehicleMake { get; set; }
[Display(Name = "Select a model")]
public IEnumerable<SelectListItem> selectVehicleModel { get; set; }
}
}
Controller:
using BLPrototype.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace BLPrototype.Controllers
{
public class TestController : Controller
{
//
// GET: /Test/
public ActionResult Index()
{
VehicleModels vm = new VehicleModels();
var model = new vmCatalogue1();
//Which is better and why?
model.selectVehicleMake = vm.getVehicleMakeList().Select(x => new SelectListItem { Value = x.vmk_id, Text = x.vmk_name });
//model.selectVehicleMake = new SelectList(vm.getVehicleMakeList(), "vmk_id", "vmk_name");
model.selectVehicleModel = new SelectList(vm.getVehicleModelList(""), "vg_id", "vg_name");
model.Title = "Title goes here";
return View(model);
}
VehicleModels vm = new VehicleModels();
[HttpPost]
public ActionResult Makes()
{
var makes = vm.getVehicleMakeList();
return Json(new SelectList(makes, "vmk_id", "vmk_name"));
}
[HttpPost]
public ActionResult Models(string vmk_id)
{
var models = vm.getVehicleModelList(vmk_id);
return Json(new SelectList(models, "vg_id", "vg_Name"));
}
}
}
View:
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>#Model.Title </title>
<script src="~/Scripts/jquery-1.7.1.min.js"></script>
<script type="text/javascript">
function getModels(vmk_id) {
$.ajax({
url: "#Url.Action("Models")",
data: { vmk_id: vmk_id },
dataType: "json",
type: "POST",
error: function () {
alert("An error occurred.");
errorHandler("error1");
},
success: function (data) {
var items = "";
$.each(data, function (i, item) {
items += "<option value=\"" + item.Value + "\">" + item.Text + "</option>";
});
$("#selectVehicleModel").html(items);
}
});
}
$(document).ready(function () {
$("#selectVehicleMake").change(function () {
getModels($("#selectVehicleMake").val());
});
});
</script>
</head>
<body>
<div>
#model BLPrototype.Models.vmCatalogue1
#using (Html.BeginForm())
{
<div class="editor-label">
#Html.LabelFor(m => m.selectVehicleMake)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.selectVehicleMake, Model.selectVehicleMake, "Please select")
</div>
<div class="editor-label">
#Html.LabelFor(m => m.selectVehicleModel)
</div>
<div class="editor-field">
#Html.DropDownListFor(m => m.selectVehicleModel, Model.selectVehicleModel, new { style = "width: 150px" })
</div>
}
</body>
</html>
The above example shows the cascading dropdowns. I've seen lots of different ways of populating a dropdownlistfor, I would like to do it via a View-Model. I'm really not sure which is the best way. Some examples seem to show just a list, some a list of selectlistitems and others just a selectlist. Could someone please tell me the difference and what is the 'better' way to do it... I know it often depends upon the application.
I would also like to be able to preselect a Make if I wish, I've seen some examples where you include the ID in various ways, and others by tagging it on to the end of the select list. None of them seem to work.
Also the Model shouldn't really show unless the make has been selected. Would I do this via CSS or another method?
Finally I've put the "Please Select" at the end of the make, so it shows. This doesn't seem like a great way of doing this. Could you please point me in the right direction?
Thank you for your time and I'm sorry for so many stupid noobish questions!
Thanks
Jay
A list of SelectListItems is more explicit and gives you a Selected property but it's more geared at multi-select lists and you no longer have access to the original list if your view requires it elsewhere.
Take a look at SelectList. It might work better for you in some cases. You can obtain one like this:
myList.ToSelectList("ID", "Description")
or
new SelectList(myList, "ID", "Description)
Add:
data-placeholder="Please Select"
in the same object that contains your "style = ..." if you want a placeholder until an option is selected.
I finally found the solution that I was after. I'll post it here in case anyone find this post in the future with similar errors.
Model:
public class VehicleModels
{
public List<vehicle_make> getVehicleMakeList()
{
using (var db = new BLEntities())
{
List<vehicle_make> vmk = db.vehicle_make.OrderBy(r => r.vmk_name).ToList();
return vmk;
}
}
public List<vehicle_group> getVehicleModelList(string vmk_id)
{
using (var db = new BLEntities())
{
List<vehicle_group> vmo = db.vehicle_group.Where(v => v.vg_vmk_id == vmk_id).OrderBy(r => r.vg_name).ToList();
return vmo;
}
}
}
public class vmCatalogue3
{
public string Title { get; set; }
public string selectedMakeId { get; set; }
public string SelectTopLine { get; set; }
[Display(Name = "Select a make")]
public SelectList selectVehicleMake { get; set; }
[Display(Name = "Select a model")]
public SelectList selectVehicleModel { get; set; }
}
Controller:
public ActionResult Index()
{
VehicleModels vm = new VehicleModels();
var model = new vmCatalogue3();
model.selectedMakeId = "870";
model.SelectTopLine = "Please Select";
model.selectVehicleMake = new SelectList(vm.getVehicleMakeList(), "vmk_id", "vmk_name");
model.selectVehicleModel = new SelectList(vm.getVehicleModelList(""), "vg_id", "vg_name");
return View(model);
}
View:
#Html.DropDownListFor(m => m.selectedMakeId, Model.selectVehicleMake, Model.SelectTopLine )
Hope that helps someone!

ValidateAntiForgeryToken with SPA architecture

I am trying to set Register and Login for Hot Towel SPA applicantion. I have created SimpleMembershipFilters and ValidateHttpAntiForgeryTokenAttribute based on the asp.net single page application template.
How do you get the
#Html.AntiForgeryToken()
code to work in the Durandal SPA pattern.
Currently I have a register.html
<section>
<h2 data-bind="text: title"></h2>
<label>Firstname:</label><input data-bind="value: firstName" type="text" />
<label>Lastname:</label><input data-bind="value: lastName" type="text" />
<label>Email:</label><input data-bind="value: emailAddress" type="text" />
<label>Company:</label><input data-bind="value: company" type="text" />
<br />
<label>Password:</label><input data-bind="value: password1" type="password" />
<label>Re-Enter Password:</label><input data-bind="value: password2" type="password" />
<input type="button" value="Register" data-bind="click: registerUser" class="btn" />
</section>
register.js:
define(['services/logger'], function (logger) {
var vm = {
activate: activate,
title: 'Register',
firstName: ko.observable(),
lastName: ko.observable(),
emailAddress: ko.observable(),
company: ko.observable(),
password1: ko.observable(),
password2: ko.observable(),
registerUser: function () {
var d = {
'FirstName': vm.firstName,
'LastName': vm.lastName,
'EmailAddress': vm.emailAddress,
'Company': vm.company,
'Password': vm.password1,
'ConfirmPassword': vm.password2
};
$.ajax({
url: 'Account/JsonRegister',
type: "POST",
data: d ,
success: function (result) {
},
error: function (result) {
}
});
},
};
return vm;
//#region Internal Methods
function activate() {
logger.log('Login Screen Activated', null, 'login', true);
return true;
}
//#endregion
});
In the $ajax call how do I pass the AntiForgeryToken? Also how do I create the token as well?
I would read this article on how to use antiforgery tokens using javascript. The article is written for WebApi but it can easily applied to an MVC controller if you want to.
The short answer is something like this:
Inside your cshtml view:
<script>
#functions{
public string TokenHeaderValue()
{
string cookieToken, formToken;
AntiForgery.GetTokens(null, out cookieToken, out formToken);
return cookieToken + ":" + formToken;
}
}
$.ajax("api/values", {
type: "post",
contentType: "application/json",
data: { }, // JSON data goes here
dataType: "json",
headers: {
'RequestVerificationToken': '#TokenHeaderValue()'
}
});
</script>
Then inside your asp.net controller you need to validate the token like so:
void ValidateRequestHeader(HttpRequestMessage request)
{
string cookieToken = "";
string formToken = "";
IEnumerable<string> tokenHeaders;
if (request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders))
{
string[] tokens = tokenHeaders.First().Split(':');
if (tokens.Length == 2)
{
cookieToken = tokens[0].Trim();
formToken = tokens[1].Trim();
}
}
AntiForgery.Validate(cookieToken, formToken);
}
The reason you want to pass it in the headers is because if you pass it as a parameter data parameter in your ajax call, inside the querystring or body, of the request. Then it will be harder for you to get the antiforgery token for all your different scenarios. Because you will have to deserialize the body and then find the token. In the headers its pretty consistent and easy to retrieve.
**edit for ray
Here is an example of an action filter which you can use to attribute web api methods to validate if a antiforgerytoken is provided.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Helpers;
using System.Web.Http.Filters;
using System.Net.Http;
using System.Net;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
using System.Threading;
namespace PAWS.Web.Classes.Filters
{
public class ValidateJsonAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter
{
public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
if (actionContext == null)
{
throw new ArgumentNullException("HttpActionContext");
}
if (actionContext.Request.Method != HttpMethod.Get)
{
return ValidateAntiForgeryToken(actionContext, cancellationToken, continuation);
}
return continuation();
}
private Task<HttpResponseMessage> FromResult(HttpResponseMessage result)
{
var source = new TaskCompletionSource<HttpResponseMessage>();
source.SetResult(result);
return source.Task;
}
private Task<HttpResponseMessage> ValidateAntiForgeryToken(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
try
{
string cookieToken = "";
string formToken = "";
IEnumerable<string> tokenHeaders;
if (actionContext.Request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders))
{
string[] tokens = tokenHeaders.First().Split(':');
if (tokens.Length == 2)
{
cookieToken = tokens[0].Trim();
formToken = tokens[1].Trim();
}
}
AntiForgery.Validate(cookieToken, formToken);
}
catch (System.Web.Mvc.HttpAntiForgeryException ex)
{
actionContext.Response = new HttpResponseMessage
{
StatusCode = HttpStatusCode.Forbidden,
RequestMessage = actionContext.ControllerContext.Request
};
return FromResult(actionContext.Response);
}
return continuation();
}
}
}
Grab value of token in JS var
var antiForgeryToken = $('input[name="__RequestVerificationToken"]').val();
Then just add to your ajax POST headers in the beforeSend function of the .ajax call
beforeSend: function (xhr, settings) {
if (settings.data != "") {
settings.data += '&';
}
settings.data += '__RequestVerificationToken=' + encodeURIComponent(antiForgeryToken);
}
I struggled a bit with this as neither of the existing answers seemed to work correctly for the case of my Durandal SPA app based on the Hot Towel Template.
I had to use a combination of Evan Larson's and curtisk's answers to get something that worked the way I think its supposed to.
To my index.cshtml page (Durandal supports cshtml alongside html) I added the following just above the </body> tag
#AntiForgery.GetHtml();
I added a custom filter class as suggested by Evan Larson, however I had to modify it to support looking up the cookie value separately and utilize __RequestVerificationToken as the name rather than RequestVerificationToken as this is what is supplied by AntiForgery.GetHtml();
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Helpers;
using System.Web.Http.Filters;
using System.Net.Http;
using System.Net;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
using System.Threading;
using System.Net.Http.Headers;
namespace mySPA.Filters
{
public class ValidateJsonAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter
{
public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
if (actionContext == null)
{
throw new ArgumentNullException("HttpActionContext");
}
if (actionContext.Request.Method != HttpMethod.Get)
{
return ValidateAntiForgeryToken(actionContext, cancellationToken, continuation);
}
return continuation();
}
private Task<HttpResponseMessage> FromResult(HttpResponseMessage result)
{
var source = new TaskCompletionSource<HttpResponseMessage>();
source.SetResult(result);
return source.Task;
}
private Task<HttpResponseMessage> ValidateAntiForgeryToken(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
try
{
string cookieToken = "";
string formToken = "";
IEnumerable<string> tokenHeaders;
if (actionContext.Request.Headers.TryGetValues("__RequestVerificationToken", out tokenHeaders))
{
formToken = tokenHeaders.First();
}
IEnumerable<CookieHeaderValue> cookies = actionContext.Request.Headers.GetCookies("__RequestVerificationToken");
CookieHeaderValue tokenCookie = cookies.First();
if (tokenCookie != null)
{
cookieToken = tokenCookie.Cookies.First().Value;
}
AntiForgery.Validate(cookieToken, formToken);
}
catch (System.Web.Mvc.HttpAntiForgeryException ex)
{
actionContext.Response = new HttpResponseMessage
{
StatusCode = HttpStatusCode.Forbidden,
RequestMessage = actionContext.ControllerContext.Request
};
return FromResult(actionContext.Response);
}
return continuation();
}
}
}
Subsequently in my App_Start/FilterConfig.cs I added the following
public static void RegisterHttpFilters(HttpFilterCollection filters)
{
filters.Add(new ValidateJsonAntiForgeryTokenAttribute());
}
In Application_Start under my Global.asax I added
FilterConfig.RegisterHttpFilters(GlobalConfiguration.Configuration.Filters);
Finally for my ajax calls I added a derivation of curtisk's input lookup to add a header to my ajax request, in the case a login request.
var formForgeryToken = $('input[name="__RequestVerificationToken"]').val();
return Q.when($.ajax({
url: '/breeze/account/login',
type: 'POST',
contentType: 'application/json',
dataType: 'json',
data: JSON.stringify(data),
headers: {
"__RequestVerificationToken": formForgeryToken
}
})).fail(handleError);
This causes all of my post requests to require a verification token which is based upon the cookie and hidden form verification tokens created by AntiForgery.GetHtml();
From my understanding this will prevent the potential for cross site scripting attacks as the attacking site would need to be able to supply both the cookie and the hidden form value to be able to verify themselves, which would be far more difficult to acquire.
If using MVC 5 read this solution!
I tried the above solutions, but they did not work for me, the Action Filter was never reached and I couldn't figure out why. The MVC version is not mentioned above, but I am going to assume it was version 4. I am using version 5 in my project and ended up with the following action filter:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Filters;
namespace SydHeller.Filters
{
public class ValidateJSONAntiForgeryHeader : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
string clientToken = filterContext.RequestContext.HttpContext.Request.Headers.Get(KEY_NAME);
if (clientToken == null)
{
throw new HttpAntiForgeryException(string.Format("Header does not contain {0}", KEY_NAME));
}
string serverToken = filterContext.HttpContext.Request.Cookies.Get(KEY_NAME).Value;
if (serverToken == null)
{
throw new HttpAntiForgeryException(string.Format("Cookies does not contain {0}", KEY_NAME));
}
System.Web.Helpers.AntiForgery.Validate(serverToken, clientToken);
}
private const string KEY_NAME = "__RequestVerificationToken";
}
}
-- Make note of the using System.Web.Mvc and using System.Web.Mvc.Filters, not the http libraries (I think that is one of the things that changed with MVC v5. --
Then just apply the filter [ValidateJSONAntiForgeryHeader] to your action (or controller) and it should get called correctly.
In my layout page right above </body> I have #AntiForgery.GetHtml();
Finally, in my Razor page, I do the ajax call as follows:
var formForgeryToken = $('input[name="__RequestVerificationToken"]').val();
$.ajax({
type: "POST",
url: serviceURL,
contentType: "application/json; charset=utf-8",
dataType: "json",
data: requestData,
headers: {
"__RequestVerificationToken": formForgeryToken
},
success: crimeDataSuccessFunc,
error: crimeDataErrorFunc
});

How can I read an uploaded file using MVC3?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Excel;
using System.Data;
namespace QuimizaReportes.Controllers
{
public class UploadController : Controller
{
public ActionResult Index()
{
//stream is supposed to be the excel file object.
IExcelDataReader excelReader = ExcelReaderFactory.CreateBinaryReader(stream);
excelReader.IsFirstRowAsColumnNames = true;
DataSet result = excelReader.AsDataSet();
while (excelReader.Read())
{
}
excelReader.Close();
return View();
}
}
}
I'm supposed to let users upload the file and read from it, then display a confirmation message that it has been saved. The question is: How can I 'get' that stream? Any suggestions?
Would this do the trick?
[HttpPost]
public ActionResult Index(HttpPostedFileBase excelFile)
{
IExcelDataReader excelReader = ExcelReaderFactory.CreateBinaryReader(excelFile.InputStream);
//Blah
}
In conjunction with something like:
<form action="/MyController/Index" enctype="multipart/form-data" method="post">
<!-- blah -->
<input type="file" id="excelFile" name="excelFile" />
<!-- blah -->
</form>