asp.net mvc making ajax call JSON - asp.net

Controller:
public ActionResult EditOrganizationMeta(int id)
{
}
[HttpPost]
[ValidateInput(false)]
public ActionResult EditOrganizationMeta(FormCollection collection)
{
}
View:
function DoAjaxCall() {
var url = '<%= Url.Action("EditOrganizationMeta", "Organization") %>';
//url = url + '/' + dd;
$.post(url, null, function(data) {
alert(data);
});
}
<input type="button" name="something" value="Save" onclick="DoAjaxCall()" />
how would i make the ajax call , i have basically two functions with the same name EditOrganizationMeta,Do the form collection will be passed automatically.Basic confusion is regarding the method call
Ok i made a call by ajax but after that My This code is not running anymore
[HttpPost]
[ValidateInput(false)]
public ActionResult EditOrganizationMeta(FormCollection collection)
{
int OrganizationId = 11;
string OrganizationName = "Ministry of Interior";
try
{
string ids = Request.Params // **getting error here some sequence is not there**
.Cast<string>()
.Where(p => p.StartsWith("button"))
.Select(p => p.Substring("button".Length))
.First();
String RealValueOfThatControl = collection[ids];
}
}
catch { }
return RedirectToAction("EditOrganizationMeta", new { id = OrganizationId });
}
I think that there is no post

You have to pass the data you want through second parameter of $.post call. The easiest way (if you want to post a form) is to use $.serialize like this:
$.post(url, $('#formId').serialize(), function(data) {
alert(data);
});
Where 'formId' is you form identifier. And don't worry about having two methods with same name, they will be distincted by HttpVerb (one will respond only to GET, while second to POST).

Related

Asp net core mvc model details not validating and passing values to controller

In the Edit method of a controller, I cannot successfully validate and pass the details of a model. But when I add new row, it validates and pass it's values to the controller.
Here is the sample output:
The two records is not passing and validating but when I add a new row, the record from new row validates and passes
Here is my code for getting the existing details
var form = $('form');
$.ajax({
url: '/Journals/EditJournalDetails',
data: {
id: #Model.Id
},
success: function (data) {
$('#journalRow').append('<tr>' + data + '</tr>');
$('tbody#journalRow>tr.checkDetails').appendTo('#checkRow');
form.data('validator', null);
$.validator.unobtrusive.parse(form);
}
});
the code for EditJournalDetails
#model IEnumerable<SimplyAccounting.Models.TransactionViewModels.JournalDetailsViewModel>
#using (Html.BeginCollectionItem("JournalDetailsViewModel"))
{
#foreach (var item in Model)
{
//row values here
}
}
Controller code:
public async Task<IActionResult> EditJournalDetails(int? id)
{
var journaldetails = await _context.JournalDetails.Where(m => m.JournalId == id).ToListAsync();
var jdvmodel = _mapper.Map<List<JournalDetailsViewModel>>(journaldetails);
foreach(var item in jdvmodel)
{
//retrieve data here
}
return PartialView("_EditJournalDetails", jdvmodel);
}
Add row code JS:
function GetRow() {
var form = $('form');
$.ajax({
url: '/Journals/CreateJournalDetails',
success: function (data) {
$('#journalRow').append('<tr>' + data + '</tr>');
$('tbody#journalRow>tr.checkDetails').appendTo('#checkRow');
form.data('validator', null);
$.validator.unobtrusive.parse(form);
}
});
}
CreateJournalDetails partialview code:
#model SimplyAccounting.Models.TransactionViewModels.JournalDetailsViewModel
#using (Html.BeginCollectionItem("JournalDetailsViewModel"))
{
//row codes here
}
Controller code:
public IActionResult CreateJournalDetails(JournalDetailsViewModel vmodel)
{
vmodel = new JournalDetailsViewModel();
//some code here
return PartialView("_CreateJournalDetails", vmodel);
}
Solve the issues using this code
View
<tbody id="journalRow">
#foreach(var item in Model.JournalDetailsViewModel)
{
#Html.Partial("_JournalDetails", item)
}
</tbody>
PartialView
#model SimplyAccounting.Models.TransactionViewModels.JournalDetailsViewModel
#using (Html.BeginCollectionItem("JournalDetailsViewModel"))
{
<tr class="checkDetails" id="#Model.Guid">
<td>
}
}

Can't pass data to asp.net core

I have a problem, I need to send data from my Angular to my ASP.NET Core server. Here is controller:
[HttpPut]
public IActionResult setCoupon(int id, string CouponCode, int DiscountPercent)
{
try
{
var coupon = new Coupon()
{
Id = id,
CouponCode = CouponCode,
DiscountPercent = DiscountPercent
};
return Ok(coupon);
}
catch (Exception)
{
return BadRequest("Wystąpił błąd");
}
}
Here is factory from ngResource (getCoupon is working):
app.factory('couponApi',
function($resource) {
return $resource("/coupon/setCoupon",
{},
{
getCoupon: {
method: "GET",
isArray: false
},
putCoupon: {
method: "PUT",
isArray: false,
}
});
});
Here is usage of factory:
$scope.addCouponCode = function(coupon) {
couponApi.putCoupon(coupon);
};
When i debug my asp.net server i found my params null or 0. I have the same problem on restangular library.
I also try this way to write controller method
[HttpPut]
public IActionResult setCoupon(Coupon coupon)
{
try
{
return Ok(coupon);
}
catch (Exception)
{
return BadRequest("Wystąpił błąd");
}
}
My json which I try to send is this
{"id":1,"couponCode":"abc","discountPercent":10}
and my Echo method send me this:
{"id":0,"couponCode":null,"discountPercent":0}
Update
Apparently in asp.net core, method need to have attribute[FromBody]
[HttpPut]
public IActionResult setCoupon([FromBody] Coupon coupon)
{
try
{
return Ok(coupon);
}
catch (Exception)
{
return BadRequest(new {errorMessage = "Wystąpił błąd"});
}
}
As Aldo says in the comments. The answer is C# expects case-sensitive matching of the json data. So:
{"id":1,"couponCode":"abc","discountPercent":10}
needs to be:
{"id":1,"CouponCode":"abc","DiscountPercent":10}
You were getting a 0 for 'discountPercent' because that is the default value of the unmatched int, whereas null is the default for a unmatched string, hence Echo returns:
{"id":0,"couponCode":null,"discountPercent":0}

Setting Up Multiple Actions

I was wondering if it was possible to have more than 1 action in the link. For example, If I wanted to have multiple links such as:
http://www.mywebsite.com/(CONTROLLER)/(ID)/(ACTION)
[http://]www.mywebsite.com/user/Micheal/EditMovies
[http://]www.mywebsite.com/user/Micheal/EditFavorites
Is there some sort of way to do this? If not, do I have to specify multiple id's in the function and then use a case to determine which page they are going to be sent to?
In my UserController.cs I have:
public ActionResult Index(string username)
{
if (username != null)
{
try
{
var userid = (Membership.GetUser(username, false).ProviderUserKey);
Users user = entity.User.Find(userid);
return View(user);
}
catch (Exception e)
{
}
}
return RedirectToAction("", "Home");
}
In my Routes I have:
routes.MapRoute(
name: "User",
url: "User/{username}",
defaults: new { controller = "User", action = "Index" }
);
What I'm trying to make it do is have additional functions for second actions so I can do something like:
User/{username}/{actionsAdditional}
And In my UserController I can put more actions which will leader to the second action actionsAdditional
public ActionResult Index(string username)
{
if (username != null)
{
try
{
var userid = (Membership.GetUser(username, false).ProviderUserKey);
Users user = entity.User.Find(userid);
return View(user);
}
catch (Exception e)
{
}
}
return RedirectToAction("", "Home");
}
public ActionResult EditFavorites()
{
//DoStuff
}
You could do this multiple ways, here's just one:
Set up a route to handle this:
routes.MapRoute("UserEditsThings",
"user/{id}/edit/{thingToEdit}",
new { controller = "UserController", action="Edit" },
new { thingToEdit = ValidThingsToEditConstraint() }
);
Then your action in the User Controller should look like this:
public ActionResult Edit(ThingToEdit thingToEdit) {
ThingToEditViewModel viewModel = new ThingToEditViewModel(thingToEdit);
return View(viewModel);
}
The RouteConstraint is what would take their input (the thingToEdit) and make sure it was valid (you could do this in a few places - like in a Custom ModelBinder):
public class ValidThingsToEditConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
//simplistic implementation simply to show what's possible.
return values['thingToEdit'] == "Favorites" || values['thingToEdit'] == "Movies";
}
}
Now, that way, you can have one method to Edit both Movies and Favorites, and you simply add a parameter to show what 'type' of thing they're editing.
If you wanted to keep your current route, you should be able to do the following:
routes.MapRoute("UserEditsThings",
"user/{id}/edit{thingToEdit}",
new { controller = "UserController", action="Edit" },
new { thingToEdit = ValidThingsToEditConstraint() }
);
I've been away from ASP.NET MVC for about 7 months, so this could be a little rusty. It has not been tested for syntax errors and bits of python may shine through. It should get you there, though.

Making TPL Async calls from mvc controller on click of submit button

Basically I want to implement simple search functionality, whenever user enters some keyword in the text box on view and clicks submit button I want to make ASYNC calls to predefined website urls using TPL Async mechanism. When I do the same with console application it works like a charm but not with ASP.NET MVC3.
I couldn't find the reason
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
[HttpPost]
public ActionResult Index(string text)
{
string[] url = { "http://www.msnbc.com", "http://www.yahoo.com",
"http://www.nytimes.com", "http://www.washingtonpost.com",
"http://www.latimes.com", "http://www.newsday.com" };
Task<string[]> webTask = this.GetWordCounts(url, text);
string[] results = null;
try
{
results = webTask.Result;
}
catch (AggregateException e)
{
}
return View("Index", results);
}
//Taken from MSDN
Task<string[]> GetWordCounts(string[] urls, string name)
{
TaskCompletionSource<string[]> tcs = new TaskCompletionSource<string[]>();
WebClient[] webClients = new WebClient[urls.Length];
object m_lock = new object();
int count = 0;
List<string> results = new List<string>();
for (int i = 0; i < urls.Length; i++)
{
webClients[i] = new WebClient();
#region callback
// Specify the callback for the DownloadStringCompleted
// event that will be raised by this WebClient instance.
webClients[i].DownloadStringCompleted += (obj, args) =>
{
if (args.Cancelled == true)
{
tcs.TrySetCanceled();
return;
}
else if (args.Error != null)
{
// Pass through to the underlying Task
// any exceptions thrown by the WebClient
// during the asynchronous operation.
tcs.TrySetException(args.Error);
return;
}
else
{
// Split the string into an array of words,
// then count the number of elements that match
// the search term.
string[] words = null;
words = args.Result.Split(' ');
string NAME = name.ToUpper();
int nameCount = (from word in words.AsParallel()
where word.ToUpper().Contains(NAME)
select word)
.Count();
// Associate the results with the url, and add new string to the array that
// the underlying Task object will return in its Result property.
results.Add(String.Format("{0} has {1} instances of {2}", args.UserState, nameCount, name));
}
// If this is the last async operation to complete,
// then set the Result property on the underlying Task.
lock (m_lock)
{
count++;
if (count == urls.Length)
{
tcs.TrySetResult(results.ToArray());
}
}
};
#endregion
// Call DownloadStringAsync for each URL.
Uri address = null;
try
{
address = new Uri(urls[i]);
// Pass the address, and also use it for the userToken
// to identify the page when the delegate is invoked.
webClients[i].DownloadStringAsync(address, address);
}
catch (UriFormatException ex)
{
// Abandon the entire operation if one url is malformed.
// Other actions are possible here.
tcs.TrySetException(ex);
return tcs.Task;
}
}
// Return the underlying Task. The client code
// waits on the Result property, and handles exceptions
// in the try-catch block there.
return tcs.Task;
}
this is my view - for now I have hard coded keyword as microsoft
#using (Html.BeginForm("Index", "Home", new { text = "Microsoft" }))
{
<input type="submit" />
}
Update: It stays forever and inside the try block of Index Post method
I would recommend you using an AsyncController for this task to avoid jeopardizing ASP.NET worker threads which is one the worst thing that might happen to an ASP.NET application => running out of worker threads. It's like running out of fuel in the middle of the desert. You most certainly die.
So let's start by writing an extension method that will allow us converting the legacy WebClient event based pattern into the new task based pattern:
public static class TaskExtensions
{
public static Task<string> DownloadStringAsTask(this string url)
{
var tcs = new TaskCompletionSource<string>(url);
var client = new WebClient();
client.DownloadStringCompleted += (sender, args) =>
{
if (args.Error != null)
{
tcs.SetException(args.Error);
}
else
{
tcs.SetResult(args.Result);
}
};
client.DownloadStringAsync(new Uri(url));
return tcs.Task;
}
}
Armed with this extension method in hand we could now define a view model that will basically reflect the requirements of our view:
public class DownloadResultViewModel
{
public string Url { get; set; }
public int WordCount { get; set; }
public string Error { get; set; }
}
Then we move on to an asyncrhonous controller that will contain 2 actions: a standard synchronous Index action that will render the search form and an asynchronous Search action that will perform the actual work:
public class HomeController : AsyncController
{
public ActionResult Index()
{
return View();
}
[AsyncTimeout(600000)]
[HttpPost]
public void SearchAsync(string searchText)
{
AsyncManager.Parameters["searchText"] = searchText;
string[] urls =
{
"http://www.msnbc.com",
"http://www.yahoo.com",
"http://www.nytimes.com",
"http://www.washingtonpost.com",
"http://www.latimes.com",
"http://www.unexistentdomainthatwillcrash.com",
"http://www.newsday.com"
};
var tasks = urls.Select(url => url.DownloadStringAsTask());
AsyncManager.OutstandingOperations.Increment(urls.Length);
Task.Factory.ContinueWhenAll(tasks.ToArray(), allTasks =>
{
var results =
from task in allTasks
let error = task.IsFaulted ? task.Exception.Message : null
let result = !task.IsFaulted ? task.Result : string.Empty
select new DownloadResultViewModel
{
Url = (string)task.AsyncState,
Error = error,
WordCount = result.Split(' ')
.Where(x => string.Equals(x, searchText, StringComparison.OrdinalIgnoreCase))
.Count()
};
AsyncManager.Parameters["results"] = results;
AsyncManager.OutstandingOperations.Decrement(urls.Length);
});
}
public ActionResult SearchCompleted(IEnumerable<DownloadResultViewModel> results)
{
return View("index", results);
}
}
Now we define an ~/Views/Home/Index.cshtml view that will contain the search logic as well as the results:
#model IEnumerable<DownloadResultViewModel>
#using (Html.BeginForm("search", null, new { searchText = "politics" }))
{
<button type="submit">Search</button>
}
#if (Model != null)
{
<h3>Search results</h3>
<table>
<thead>
<tr>
<th>Url</th>
<th>Word count</th>
</tr>
</thead>
<tbody>
#Html.DisplayForModel()
</tbody>
</table>
}
And of course the corresponding display template that will be rendered automatically for each element of our model (~/Views/Shared/DisplayTemplates/DownloadResultViewModel.cshtml):
#model DownloadResultViewModel
<tr>
<td>#Html.DisplayFor(x => x.Url)</td>
<td>
#if (Model.Error != null)
{
#Html.DisplayFor(x => x.Error)
}
else
{
#Html.DisplayFor(x => x.WordCount)
}
</td>
</tr>
Now, since the search operation could take quite a long time your users could quickly get bored without being able to use some of the other hundredths of functionalities that your webpage has to offer them.
In this case it is absolutely trivial to invoke the Search controller action using an AJAX request and showing a spinner to inform the users that their search is in progress but without freezing the webpage allowing them to do other things (without navigating away from the page obviously).
So let's do that, shall we?
We start by externalizing the results into a partial (~/Views/Home/_Results.cshtml) without touching at the display template:
#model IEnumerable<DownloadResultViewModel>
#if (Model != null)
{
<h3>Search results</h3>
<table>
<thead>
<tr>
<th>Url</th>
<th>Word count</th>
</tr>
</thead>
<tbody>
#Html.DisplayForModel()
</tbody>
</table>
}
and we adapt our ~/Views/Home/Index.cshtml view to use this partial:
#model IEnumerable<DownloadResultViewModel>
#using (Html.BeginForm("search", null, new { searchText = "politics" }))
{
<button type="submit">Search</button>
}
<div id="results">
#Html.Partial("_Results")
</div>
and of course the SearchCompleted controller action that must now return only the partial result:
public ActionResult SearchCompleted(IEnumerable<DownloadResultViewModel> results)
{
return PartialView("_Results", results);
}
Now all that's left is to write a simple javascript that will AJAXify our search form. So this could happen into a separate js that will reference in our layout:
$(function () {
$('form').submit(function () {
$.ajax({
url: this.action,
type: this.method,
success: function (results) {
$('#results').html(results);
}
});
return false;
});
});
Depending on whether you referenced this script in the <head> section or at the end of the body you might not need to wrap it in a document.ready. If the script is at the end you could remove the wrapping document.ready function from my example.
And the last part is to give some visual indication to the user that the site is actually performing a search. This could be done using a global ajax event handler that we might subscribe to:
$(function () {
$(document).ajaxStart(function () {
$('#results').html('searching ...');
});
});

JSON returned data formatting

I'm using code below to get JSON data:
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult getBranchViaJson()
{
Json(getBranchList(AppSession.BranchID.Value));
}
private object getBranchList(int n)
{
var mybranchList = from p in getBranchs(n)
select new { p.Code, p.Name };
return mybranchList.ToArray();
}
Client side retain value :
[{"Code":000,"Name":"Milan"},
{"Code":001,"Name":"Istanbul"},
{"Code":002,"Name":"Baku"},]
But I want to get like this:
[{000:"Milan"},{001:"Istanbul"},{002:"Baku"}]
What is the best way to do this?
First things first:
[{000:"Milan"},{001:"Istanbul"},{002:"Baku"}]
is invalid JSON. Properties must be quoted like so:
[{"000":"Milan"},{"001":"Istanbul"},{"002":"Baku"}]
In order to achieve this output you could use a Dictionary<string, string> that the JavaScriptSerializer will serialize to the desired output. So simply call the ToDictionary extension method on your model in order to convert it to a dictionary:
Like that:
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult getBranchViaJson()
{
var branches =
from p in getBranchs(AppSession.BranchID.Value)
select new { p.Code, p.Name };
var model = branches.ToDictionary(x => x.Code, x => x.Name);
return Json(new[] { model }, JsonRequestBehavior.AllowGet);
}
or if you want to keep your private method which returns an object you could make it return a dictionary:
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult getBranchViaJson()
{
return Json(getBranchList(AppSession.BranchID.Value), JsonRequestBehavior.AllowGet);
}
private object getBranchList(int n)
{
var mybranchList = from p in getBranchs(n)
select new { p.Code, p.Name };
return new[] { mybranchList.ToDictionary(x => x.Code, x => x.Name) };
}
Notice that I used new[] { model }. That's because otherwise the JavaScriptSerializer won't produce a javascript array as required but a simple javascript object.
Remark: notice that I have added JsonRequestBehavior.AllowGet so that this controller action can be consumed with a GET request which is disabled by default for actions returning JSON responses.

Resources