I have the following ASMX web service:
// removed for brevity //
namespace AtomicService
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[ScriptService]
public class Assets : WebService
{
private static readonly ILog Log = LogManager.GetLogger(typeof(Validation));
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string CityCreate(string cityname, string state, string country,
decimal timezoneoffset, decimal lat, decimal lon)
{
var response = new Dictionary<string, string>();
if(string.IsNullOrEmpty(cityname) || (string.IsNullOrEmpty(country)))
{
response.Add("Response", "empty");
return JsonConvert.SerializeObject(response, Formatting.Indented);
}
int tzid;
int ctyid;
try
{
tzid = AtomicCore.TimezoneObject.GetTimezoneIdByGMTOffset(timezoneoffset);
var cty = AtomicCore.CountryObject.GetCountry(country);
ctyid = cty.CountryId;
}
catch (Exception)
{
response.Add("Response", "errordb");
return JsonConvert.SerializeObject(response, Formatting.Indented);
}
if(AtomicCore.Validation.DoesCityAlreadyExistByLatLon(cityname, country, lat, lon))
{
response.Add("Response", "exists");
return JsonConvert.SerializeObject(response, Formatting.Indented);
}
const string pattern = #"^(?<lat>(-?(90|(\d|[1-8]\d)(\.\d{1,6}){0,1})))\,{1}(?<long>(-?(180|(\d|\d\d|1[0-7]\d)(\.\d{1,6}){0,1})))$";
var check = new Regex(pattern, RegexOptions.IgnorePatternWhitespace);
bool valid = check.IsMatch(lat + "," + lon);
if(valid == false)
{
response.Add("Response", "badlatlon");
return JsonConvert.SerializeObject(response, Formatting.Indented);
}
BasicConfigurator.Configure();
Log.Info("User created city; name:" + cityname + ", state:" + state + ", countryid:" + ctyid + ", timezoneid:" + tzid + ", lat:" + lat + ", lon:" + lon + "");
//will return id of created city or 0.
var result = AtomicCore.CityObject.CreateCity(cityname, state, ctyid, tzid, lat.ToString(), lon.ToString(), string.Empty);
response.Add("Response", result > 0 ? "True" : "errordb");
return JsonConvert.SerializeObject(response, Formatting.Indented);
}
}
}
This is called by a JQuery $.ajax call:
$.ajax({
type: "POST",
url: "http://<%=Atomic.UI.Helpers.CurrentServer()%>/AtomicService/Assets.asmx/CityCreate",
data: "{'cityname':'" + $('#<%=litCity.ClientID%>').val() + "','state':'" + $('#<%=litState.ClientID%>').val() + "','country':'<%=Session["BusinessCountry"]%>','timezoneoffset':'" + $('#<%=litTimezone.ClientID%>').val() + "','lat':'" + $('#<%=litLat.ClientID%>').val() + "','lon':'" + $('#<%=litLng.ClientID%>').val() + "'}",
contentType: "application/json",
dataType: "json",
success: function (msg) {
if (msg["d"].length > 0) {
var data = $.parseJSON(msg.d);
if (data.Response > 0) {
//everything has been saved, ideally we
//want to get the cityid and pass it back
//to the map page so we can select it...
alert('Hazzah!');
$(this).dialog('close');
} else {
if(data.Response == 'errordb')
{
alert("db");
}
if(data.Response == 'exists')
{
alert("exists");
}
if(data.Response == 'badlatlon')
{
alert("badlatlon");
}
if(data.Response == 'empty')
{
alert("empty");
}
$('#serviceloader').hide();
$('#<%=txtFindMyCity.ClientID%>:input').attr('disabled', false);
$('#erroroccured').show('slow');
$('#errortext').html("Unfortunately, we can't save this right now. We think this city may already exist within Atomic. Could you please check carefully and try again? If this is an obvious error, please contact us and we'll get you started.");
}
} else {
$('#serviceloader').hide();
$('#<%=txtFindMyCity.ClientID%>:input').attr('disabled', false);
$('#erroroccured').show('slow');
$('#errortext').html("Unfortunately, we can't save this right now. Our data service is not responding. Could you perhaps try again in a few minutes? We're very sorry. Please contact us if this continues to happen.");
}
},
error: function (msg) {
$('#serviceloader').hide();
$('#<%=txtFindMyCity.ClientID%>:input').attr('disabled', false);
$('#erroroccured').show('slow');
$('#errortext').html("Unfortunately, we can't save this right now. Perhaps something has gone wrong with some of our data services. Why not try again? If the problem persists, please let us know and we'll get you started.");
}
});
And despite this, I always receive { "Response" : "False" }. I think this may be a cache problem - but I simply can't get the AJAX to run the service. When I go directly to asset.asmx and invoke the service, the CreateCity method runs correctly.
This is a classic wood for the trees - I have looked at it too long and I'm giving up the will to live...
Thus, the question is: I'd like the CreateCity service work correctly, when called by $.ajax, and not receive a { "Response" : "False" } response. Can anyone provide any direction, help or assistance on how to achieve this with the code I have provided? Please bear in mind that I believe that my service may be caching (hence the { "Response" : "False" } response)...
Help, advice, flames and general comments welcomed...
You don't need to manually JSON serialize the response. This is automatically handled by script enabled services. Simply return a strongly typed object from your web method. Same for the input. Also you must ensure to properly URL encode the request parameters. So start by defining models:
public class City
{
public string Cityname { get; set; }
public string State { get; set; }
public string Country { get; set; }
public decimal Timezoneoffset { get; set; }
public decimal Lat { get; set; }
public decimal Lon { get; set; }
}
public class Response
{
public string Message { get; set; }
public bool IsSuccess { get; set; }
}
and then:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[ScriptService]
public class Assets : WebService
{
private static readonly ILog Log = LogManager.GetLogger(typeof(Validation));
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public Response CityCreate(City city)
{
var response = new Response();
// ... process and populate the return message,
// set the IsSuccess boolean property which will
// be used by the client (see next...)
return response;
}
}
and on the client side:
$.ajax({
type: 'POST',
url: '<%= ResolveUrl("~/Assets.asmx/CityCreate") %>',
contentType: 'application/json',
dataType: 'json',
data: JSON.stringify({
cityname: $('#<%=litCity.ClientID%>').val(),
state: $('#<%=litState.ClientID%>').val(),
country: '<%=Session["BusinessCountry"]%>',
timezoneoffset: $('#<%=litTimezone.ClientID%>').val(),
lat: $('#<%=litLat.ClientID%>').val(),
lon: $('#<%=litLng.ClientID%>').val()
}),
success: function (result) {
// result.d will represent the response so you could:
if (result.d.IsSuccess) {
...
} else {
...
}
};
});
You can add cache:false to your %.ajax call to make sure it isn't being cached. Have you popped a breakpoint on the service to double check what's being passed through from your jQuery?
Related
I've been looking for a solution to this case for hours, and I did not find anything that worked out for me.
Here we use the comma for decimal separator, and when I send a value like "15,50", in my controller I get the value of the model as "1550", and it only makes sense if I send "15.50".
I covered the following topics, and nothing worked.
Set CultureInfo in Asp.net Core to have a . as CurrencyDecimalSeparator instead of ,
Aspnet Core Decimal binding not working on non English Culture
I am sending the form with ajax, using the $form.serializeArray() as below:
function getFormData(xform) {
var $form = $('#' + xform);
var unindexed_array = $form.serializeArray();
var indexed_array = {};
$.map(unindexed_array, function (n, i) {
indexed_array[n['name']] = n['value'];
});
return indexed_array;
}
send:
function PostFormAjax(controller, metodo, params, redir, divacao, reloadgrid) {
if (params != null) {
var formData = new FormData();
var json = $.parseJSON(JSON.stringify(params));
$(json).each(function (i, val) {
$.each(val, function (k, v) {
console.log(k + " : " + v);
formData.append(k, v);
});
});
}
$.ajax({
url: '/' + controller + '/' + metodo,
data: JSON.stringify(params),
contentType: 'application/json',
type: 'POST',
success: function (data) {
AjaxFim(metodo, data, redir, divacao, reloadgrid);
}
});
}
My controller:
[HttpPost]
public IActionResult GravaProduto([FromBody] Produtos produto)
{
if (ModelState.IsValid)
{
//produto.Valorcusto is 1550 and not 15,50 as it was posted
//produto.Valorvenda is 1550 and not 15,50 as it was posted
}
}
My Model.cs
public partial class Produtos
{
public int Cod { get; set; }
public string Descricao { get; set; }
public decimal Valorcusto { get; set; }
public decimal Valorvenda { get; set; }
}
I tried to make a replace in formData.append(k, v.replace(',', '.')); and also does not work, I also would not know which field is a decimal.
What do I have to do? because I'm lost, what should have been simpler became more complicated.
What I did to keep working until I found a solution was:
Wear a mask according to my regional setting:
$('.stValor').mask("#.###.##0,00", { reverse: true });
And before posting the form, I switch to the accepted formatting:
$('#fCadAltProd').validator().on('submit', function (e) {
if (e.isDefaultPrevented()) {
} else {
e.preventDefault();
$('.stValor').mask("#,###,##0.00", { reverse: true });
//Ajax post here
}
});
Here we use the comma for decimal separator, and when I send a value like "15,50", in my controller I get the value of the model as "1550", and it only makes sense if I send "15.50".
Create a custom model binder using the Norwegian culture, because Norway also uses the comma decimal separator. You might also want to specify certain multiple allowed number styles.
Here is one that still needs to have error handling. It gives you the basic idea, though, and you can build on it from here. What I would do it copy most of the logic from the built-in DecimalModelBinder.
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Microsoft.Extensions.Logging;
namespace AspNetCorePlayground.Models
{
public class MyFirstModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var valueProviderResult = bindingContext
.ValueProvider
.GetValue(bindingContext.ModelName);
var cultureInfo = new CultureInfo("no"); // Norwegian
decimal.TryParse(
valueProviderResult.FirstValue,
// add more NumberStyles as necessary
NumberStyles.AllowDecimalPoint,
cultureInfo,
out var model);
bindingContext
.ModelState
.SetModelValue(bindingContext.ModelName, valueProviderResult);
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
}
}
}
Then decorate your class like this:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
namespace AspNetCorePlayground.Models
{
public class MyFirstModelBinderTest
{
[ModelBinder(BinderType = typeof(MyFirstModelBinder))]
public decimal SomeDecimal { get; set; }
}
}
I tested it on a controller:
[HttpGet("test")]
public IActionResult TestMyFirstModelBinder(MyFirstModelBinderTest model)
{
return Json(model);
}
This is the result:
Use this plugin jquery.serializeToJSON
and change your getFormData() function to
function getFormData(xform) {
var $form = $('#' + xform);
var obj = $form.serializeToJSON({
parseFloat: {
condition: ".stValor,.stQnt,.stDesconto",
nanToZero: true,
getInputValue: function (i) {
return i.val().split(".").join("").replace(",", ".");
}
}
});
return obj;
}
parseFloat.getInputValue: function(){}, By default, returns the input value without commas, not an error occurs in conversion. if your location uses comma for decimal separation, for example in German or Brazil, you can change to
function(i){
return i.val().split(".").join("").replace(",", ".");
}
This will do all the work for you.
I am trying to post List of object (or array of object) to c# Webmethod. I am understanding how to receive as parameter in the method and convert into local List of object?.
for (var i = 0; i < usersInfo.length; i++) {
user = {
UserName : usersInfo[i].UserName,
Email : usersInfo[i].Email,
Status : status
};
users.push(user);
}
var results = "";
$('#lblError').val('');
if (users.length > 0) {
$.ajax({
type: 'POST',
contentType: "application/json; charset=utf-8",
url: 'UserValidation.aspx/ShowResults',
data: "{'UsersInfo':'" + JSON.stringify(users) + "'}",
async: false,
success: function (data) {
results = data.d;
$('#lblError').val(results);
},
error: function (xhr, status, error) {
var exception = JSON.parse(xhr.responseText);
alert(exception.Message);
}
});
}
Code behind
[WebMethod]
public static void ShowResults(//Here how receive list object from javascript)
{
//convert parameter to List<UsersInfo>
}
public partial class UsersInfo
{
public string UserName { get; set; }
public string Email { get; set; }
public string Status { get; set; }
}
Try to replace this line
data: JSON.stringify({ UsersInfo: users}),
James you are the right track; you need to define the correct type for the ShowResults parameter so that the binding will work and bind the incoming json to your UsersInfo class.
Your UsersInfo class appears to be a simple POCO so should bind without any custom binding logic :
[WebMethod]
public static void ShowResults(List<UsersInfo> UsersInfo)
{
//No need to convert
}
I have a problem, I cannot add custom objects to my List. However, if I add some predefined objects (strings, integers..) my code works just fine.
This is my class which is always returned on all ajax calls to this controller, it contains boolean Status and List of objects.
public class returnData
{
public bool status { get; set; }
public List<object> data { get; set; }
}
This is the class for the object I want to add to this list:
public class file
{
public string ID { get; set; }
public string Name { get; set; }
public string Type { get; set; }
}
The code where I use this:
returnData data = new returnData();
...
DriveFile file = JsonConvert.DeserializeObject<DriveFile>(Json);
file f = new file();
if (file.mimeType == "application/vnd.google-apps.folder")
{
f.Type = "folder";
f.ID = file.id;
f.Name = file.title;
data.data.Add(f);
}
The error I get has no useful info, as this code compiles and the error is in Chrome Console log when the ajax is executed.
Image of google chrome console
However, when I use this line of code
data.data.add("some string");
my function will work flawlessly and return Object which contains boolean Status and List of objects (strings, integers..)
So back to my question, how do I add my objects to this list?
EDIT: There are no server side errors, the code compiles and runs just fine, so this probably is some jquery/ajax error.
This is the ajax code for my debugger:
86 $.ajax({
87 url: $('#url').val(),
88 type: $('#type option:selected').val(),
89 contentType: "application/json; charset=utf-8",
90 dataType: "json",
91 data: $('#data').val(),
92 success: function (result){
93 console.log(result)
94 },
95 error: function (err){
96 console.log(err)
97 }
98 });
Here is the complete method, but the method seems to be OK, it is the ajax or something to do with jquery I guess.
[OperationContract]
public returnData listChildren(string folderId)
{
returnData data = new returnData();
List<object> myList= new List<object>();
bool status = true;
try
{
string Json = Response("https://www.googleapis.com/drive/v2/files/" + folderId + "/children", "GET");
//get the children list
if (!Json.Contains("error"))
{
DriveChildlist list = JsonConvert.DeserializeObject<DriveChildlist>(Json);
foreach (DriveChildren child in list.items)
{
string uriString = child.childLink;
//get the info for each child in the list
Json = Response(uriString, "GET");
if (!Json.Contains("error"))
{
DriveFile file = JsonConvert.DeserializeObject<DriveFile>(Json);
file f = new file();
if (file.mimeType == "application/vnd.google-apps.folder")
{
f.Type = "folder";
f.ID = file.id;
f.Name = file.title;
data.data.Add(f);
}
else if (file.mimeType == "application/myMimeType")
{
f.Type = "file";
f.ID = file.id;
f.Name = file.title;
data.data.Add(f);
}
}
else
{
status = false;
}
}
}
else
{
status = false;
}
}
catch(Exception)
{
status = false;
}
data.status = status;
if (!status)
{
data.data = null;
//data.data is null if status is false
}
return data;
}
As written your C# code won't work but will compile. It will throw an error when the ajax is called and you may never see the error message (depending on how your system is setup).
Here is correct code (given your snippet)
returnData data = new returnData();
data.data = new List<object>();
// rest of your code.
I have solved this using the Newtonsoft.Json. I have serialized the object using this code:
string jsondata = JsonConvert.SerializeObject(data);
and then I returned the serialized string instead of object. Looks like visual studio development center failed to serialize my object, even after adding [Serializable()] to my class. Any info on that?
I have an Ajax call (for a HighChartsDB chart) in a WebForm application that calls a webservice, which uses a WebRequest to call an MVC action in another application which returns a JsonResult.
I manage to pass the data back to the ajax call but the data I get back is not parsed as a json object but just a string.
My class:
public class CategoryDataViewModel
{
public string name { get; set; }
public List<int> data { get; set; }
public double pointStart { get; set; }
public int pointInterval { get { return 86400000; } }
}
My ajax function called by the highcharts:
function getBugs(mileId) {
var results;
$.ajax({
type: 'GET',
url: 'Services/WebService.svc/GetData',
contentType: "application/json; charset=utf-8",
async: false,
data: { "mileId": parseInt(mileId) },
dataType: "json",
success: function (data) {
console.log(data);
results = data;
}
});
return results;
}
And finally my WebService
public class WebService : IWebService
{
public string GetData(int mileId)
{
string url = "http://localhost:63418/Home/GetWoWData?mileId=" + mileId;
WebRequest wr = WebRequest.Create(url);
using (var response= (HttpWebResponse)wr.GetResponse())
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
var objText = reader.ReadToEnd();
return objText;
}
}
}
}
With this when I console.log(data) on the ajax call I get:
[{\"name\":\"Sedan\",\"data\":[30,30,30,30,35],\"pointStart\":1307836800000,\"pointInterval\":86400000},{\"name\":\"Low\",\"data\":[800,800,800,826,1694],\"pointStart\":1307836800000,\"pointInterval\":86400000},{\"name\":\"Medium\",\"data\":[180,180,180,186,317],\"pointStart\":1307836800000,\"pointInterval\":86400000},{\"name\":\"High\",\"data\":[29,29,29,34,73],\"pointStart\":1307836800000,\"pointInterval\":86400000},{\"name\":\"Truck\",\"data\":[6,6,6,6,13],\"pointStart\":1307836800000,\"pointInterval\":86400000},{\"name\":\"SUV\",\"data\":[-172,-172,-172,-179,-239],\"pointStart\":1307836800000,\"pointInterval\":86400000},{\"name\":\"Convertible\",\"data\":[0,0,0,0,-404],\"pointStart\":1307836800000,\"pointInterval\":86400000},{\"name\":\"Limo\",\"data\":[-7,-7,-7,-8,-214],\"pointStart\":1307836800000,\"pointInterval\":86400000}]
I can't seem to manage to pass back into a proper Json object. I tried converting it back to my CategoryDataViewModel with this in my webservice:
var myojb = new CategoryDataViewModel ();
using (var response = (HttpWebResponse)wr.GetResponse())
{
using (var reader = new StreamReader(response .GetResponseStream()))
{
JavaScriptSerializer js = new JavaScriptSerializer();
var objText = reader.ReadToEnd();
myojb = (CategoryDataViewModel )js.Deserialize(objText, typeof(CategoryDataViewModel ));
}
}
return myojb;
But then I get Type 'Test.CategoryDataViewModel' is not supported for deserialization of an array.
Change:
myojb = (CategoryDataViewModel )js.Deserialize(objText, typeof(CategoryDataViewModel ));
to:
myojb = (List<CategoryDataViewModel> )js.Deserialize(objText, typeof(List<CategoryDataViewModel>));
and you should be fine. The array will de-serialize to a list no problem.
I've seen a similar thing before, I think you might need to change myObj to a list.
List<CategoryDataViewModel> myObjs = new List<CategoryDataViewModel>();
...
myObjs = js.Deserialize<List<CategoryDataViewModel>>(objText);
Client-Side I'm trying to capture the fields like this:
// Initialize the object, before adding data to it.
// { } is declarative shorthand for new Object().
var NewSubscriber = { };
NewSubscriber.FirstName = $("#FirstName").val();
NewSubscriber.LastName = $("#LastName").val();
NewSubscriber.Email = $("#Email").val();
NewSubscriber.subscriptionID = $("#subscriptionID").val();
NewSubscriberNewPerson.Password = "NewPassword1";
NewSubscriber.brokerID = "239432904812";
// Create a data transfer object (DTO) with the proper structure.
var DTO = { 'NewSubscriber' : NewSubscriber };
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "NewSubscriberService.asmx/AddDigitalSubscriber",
data: JSON.stringify(DTO),
dataType: "json"
});
Now here's the problem I'm running into. How do I send these parameters and set them in the web service using C# or vb.net if it's easier? Any help is greatly appreciated
Here is what I have so far:
public class Service1 : System.Web.Services.WebService
{
public SubNameSpace.WebServiceSubBook.drmProfile _profile;
[WebMethod]
public string SetProfileData (object DTO) {
SetProfile (DTO);
}
[WebMethod]
public class SetProfileData (SubNameSpace.WebServiceSubBook.drmProfile _profile;) {
this._profile = _profile;
return "success";
}
}
}
SetProfile is an operation within the web service. SetProfileRequest is the message in the operation. I want to set certain parameters and then list other parameters in the code-behind file such as:
access_time = 30;
I'm completely lost...help!
Front-End Coder Lost in C# Translation
Your javascript object's first 'head' id NewSubscriber must match your web methods signature, for example:
you are calling url: "NewSubscriberService.asmx/AddDigitalSubscriber", with var DTO = { 'NewSubscriber' : NewSubscriber };
So you need something like this:
[WebMethod]
public string AddDigitalSubscriber(NewSubscriber NewSubscriber)
{
string status = string.Empty;
// Add Subscriber...
string emailFromJavascript = NewSubscriber.Email;
// do something
return status;
}
You will need a class in .NET like the following to match with your javascript object:
//... Class in .NET
public class NewSubscriber
{
public string FirstName;
public string LastName;
public string Email;
public int subscriptionID;
public string Password;
public string brokerID;
}
So the objects match and the names match.