i'm making a request do a asp.net webapi Post Method, and i'm not beeing able to get a request variable.
Request
jQuery.ajax({ url: sURL, type: 'POST', data: {var1:"mytext"}, async: false, dataType: 'json', contentType: 'application/x-www-form-urlencoded; charset=UTF-8' })
.done(function (data) {
...
});
WEB API Fnx
[AcceptVerbs("POST")]
[ActionName("myActionName")]
public void DoSomeStuff([FromBody]dynamic value)
{
//first way
var x = value.var1;
//Second way
var y = Request("var1");
}
i Cannot obtain the var1 content in both ways... (unless i create a class for that)
how should i do that?
First way:
public void Post([FromBody]dynamic value)
{
var x = value.var1.Value; // JToken
}
Note that value.Property actually returns a JToken instance so to get it's value you need to call value.Property.Value.
Second way:
public async Task Post()
{
dynamic obj = await Request.Content.ReadAsAsync<JObject>();
var y = obj.var1;
}
Both of the above work using Fiddler. If the first option isn't working for you, try setting the content type to application/json to ensure that the JsonMediaTypeFormatter is used to deserialize the content.
After banging my head around for a while on this and trying many different things I ended up putting some breakpoints on the API server and found the key value pairs stuffed down in the request. After I knew where they were, it was easy to access them. However, I have only found this method to work with WebClient.UploadString. However, it does work easily enough and allows you to load up as many parameters as you like and very easily access them server side. Note that I am targeting .net 4.5.
CLIENT SIDE
// Client request to POST the parameters and capture the response
public string webClientPostQuery(string user, string pass, string controller)
{
string response = "";
string parameters = "u=" + user + "&p=" + pass; // Add all parameters here.
// POST parameters could also easily be passed as a string through the method.
Uri uri = new Uri("http://localhost:50000/api/" + controller);
// This was written to work for many authorized controllers.
using (WebClient wc = new WebClient())
{
try
{
wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
response = wc.UploadString(uri, login);
}
catch (WebException myexp)
{
// Do something with this exception.
// I wrote a specific error handler that runs on the response elsewhere so,
// I just swallow it, not best practice, but I didn't think of a better way
}
}
return response;
}
SERVER SIDE
// In the Controller method which handles the POST request, call this helper:
string someKeyValue = getFormKeyValue("someKey");
// This value can now be used anywhere in the Controller.
// Do note that it could be blank or whitespace.
// This method just gets the first value that matches the key.
// Most key's you are sending only have one value. This checks that assumption.
// More logic could be added to deal with multiple values easily enough.
public string getFormKeyValue(string key)
{
string[] values;
string value = "";
try
{
values = HttpContext.Current.Request.Form.GetValues(key);
if (values.Length >= 1)
value = values[0];
}
catch (Exception exp) { /* do something with this */ }
return value;
}
For more info on how to handle multi-value Request.Form Key/Value pairs, see:
http://msdn.microsoft.com/en-us/library/6c3yckfw(v=vs.110).aspx
I searched all morning to find an answer that depicted both client and server code, then finally figured it out.
Brief intro - The UI is an MVC 4.5 project that implements a standard view. The server side is an MVC 4.5 WebApi. The objective was to POST the model as JSON and subsequently update a database. It was my responsibility to code both the UI and backend. Below is the code. This worked for me.
Model
public class Team
{
public int Ident { get; set; }
public string Tricode { get; set; }
public string TeamName { get; set; }
public string DisplayName { get; set; }
public string Division { get; set; }
public string LogoPath { get; set; }
}
Client Side (UI Controller)
private string UpdateTeam(Team team)
{
dynamic json = JsonConvert.SerializeObject(team);
string uri = #"http://localhost/MyWebApi/api/PlayerChart/PostUpdateTeam";
try
{
WebRequest request = WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json; charset=utf-8";
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
WebResponse response = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(response.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
}
catch (Exception e)
{
msg = e.Message;
}
}
Server Side (WebApi Controller)
[Route("api/PlayerChart/PostUpdateTeam")]
[HttpPost]
public string PostUpdateTeam(HttpRequestMessage context)
{
var contentResult = context.Content.ReadAsStringAsync();
string result = contentResult.Result;
Team team = JsonConvert.DeserializeObject<Team>(result);
//(proceed and update database)
}
WebApiConfig (route)
config.Routes.MapHttpRoute(
name: "PostUpdateTeam",
routeTemplate: "api/PlayerChart/PostUpdateTeam/{context}",
defaults: new { context = RouteParameter.Optional }
);
Try this.
public string Post(FormDataCollection form) {
string par1 = form.Get("par1");
// ...
}
try using following way
[AcceptVerbs("POST")]
[ActionName("myActionName")]
public static void DoSomeStuff(var value)
{
//first way
var x = value;
}
Related
I have an Asp.net web api with one method that receive a crypted string with variable length, my problem is it string some times could take a length near 5000.
When that method receive a string under 1930 length it process everything ok, but for lengths over 1929 returns
404 Operation returned an invalid status code 'BadRequest'
I changed method GET to POST but problem persists.
I changed filter options on server to very very long limits, but problem persists
This is my controller:
public class LicencingManagerController : ApiController
{
[HttpPost]
[Route(nameof(SaveCustomer2))]
public string SaveCustomer2(string custInfo)
{
return $"ItsOk = {custInfo}";
}
}
Actually I made calls to controller using autogenerated c# client by AutoRest 2.0.483.
I tried hand building PostAsync Request using HttpClient but nothing works.
string custInfo = "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";
var pairs = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("custInfo", custInfo)
};
var content = new FormUrlEncodedContent(pairs);
var client = new HttpClient();
// call sync
var response = client.PostAsync($"{Modelos.Shared.HttpsServicesReference.Licencing}/LicencingAPI/SaveCustomer2", content).Result;
if (response.IsSuccessStatusCode)
{
}
What is the right way to process this controller call?
There is another approach to perform this ?
Create model to hold data
public class Customer {
public string CustumerInfo { get; set; }
}
Update API to expect model in body of request
public class LicencingManagerController : ApiController {
[HttpPost]
[Route(nameof(SaveCustomer2))]
public IHttpActionResult SaveCustomer2([FromBody]Customer model) {
if(!ModelState.IsValid)
return BadRequest(ModelState);
var custInfo = model.CustumerInfo;
return Ok($"ItsOk = {custInfo}");
}
}
Post content to API in body of the request like you did before
string custInfo = "H4sIAAAAAAAEAA...";
string url = $"{Modelos.Shared.HttpsServicesReference.Licencing}/LicencingAPI/SaveCustomer2";
var pairs = new List<KeyValuePair<string, string>> {
new KeyValuePair<string, string>("CustumerInfo", custInfo)
};
var content = new FormUrlEncodedContent(pairs);
var client = new HttpClient();
var response = await client.PostAsync(url, content);
if (response.IsSuccessStatusCode) {
}
Does anyone have a full implementation demo of reCaptcha V3 in ASP.NET?
I found this article: Google Recaptcha v3 example demo
At the moment I am using reCaptcha V2 with the following code:
public bool RecaptchaValidate()
{
string Response = Request.Form["g-recaptcha-response"];//Getting Response String Append to Post Method
bool Valid = false;
//Request to Google Server
var CaptchaSiteKey = Settings["NewUserRegCaptchaSecretSiteKey"].ToString();
HttpWebRequest req = (HttpWebRequest)WebRequest.Create
(" https://www.google.com/recaptcha/api/siteverify?secret=" + CaptchaSiteKey + "&response=" + Response);
try
{
//Google recaptcha Response
using (WebResponse wResponse = req.GetResponse())
{
using (StreamReader readStream = new StreamReader(wResponse.GetResponseStream()))
{
string jsonResponse = readStream.ReadToEnd();
JavaScriptSerializer js = new JavaScriptSerializer();
ReCaptchaObject data = js.Deserialize<ReCaptchaObject>(jsonResponse);// Deserialize Json
Valid = Convert.ToBoolean(data.success);
}
}
return Valid;
}
catch (WebException ex)
{
throw ex;
}
}
On the view.ascx page I have:
<%# Register TagPrefix="recaptcha" Namespace="Recaptcha" Assembly="Recaptcha" %>
<script src='https://www.google.com/recaptcha/api.js'></script>
<scrip>
var recap = grecaptcha.getResponse();
if (recap.length == 0) {
$("#verifyhuman").css("display", "block");
}
</script>
<div class="g-recaptcha" data-sitekey="<%=ReCaptchaPublicKey%>" id="recaptcha" data-callback="recaptchaCallback"></div>
The simplest implementation:
In your cshtml file (at the top)
#section Scripts
{
<script src="https://www.google.com/recaptcha/api.js?render=your site key"></script>
<script>
grecaptcha.ready(function () {
grecaptcha.execute('your site key', { action: 'homepage' }).then(function (token) {
document.getElementById("foo").value = token;
});
});
</script>
}
In your cshtml, inside the form (just before </form>):
<input type="hidden" id="foo" name="foo" />
A function inside your Pagemodel class. See the documentation for the response object:
public static bool ReCaptchaPassed(string gRecaptchaResponse)
{
HttpClient httpClient = new HttpClient();
var res = httpClient.GetAsync($"https://www.google.com/recaptcha/api/siteverify?secret=your secret key no quotes&response={gRecaptchaResponse}").Result;
if (res.StatusCode != HttpStatusCode.OK)
{
return false;
}
string JSONres = res.Content.ReadAsStringAsync().Result;
dynamic JSONdata = JObject.Parse(JSONres);
if (JSONdata.success != "true" || JSONdata.score <= 0.5m)
{
return false;
}
return true;
}
Finally, inside your OnPostAsync() handler, at the top:
if (!ModelState.IsValid)
{
return Page();
}
else
{
if (!ReCaptchaPassed(Request.Form["foo"]))
{
ModelState.AddModelError(string.Empty, "You failed the CAPTCHA.");
return Page();
}
}
Edit : I have added a demo project . Check this github repository .
https://github.com/NIHAR-SARKAR/GoogleRecaptchav3-example-In-asp.net
From frontend (.aspx page) you need to send ajax request to pass the token to backend server . Using "recaptcha.execute" U can get the response , and pass the token using ajax request .Please check the code block .
<script src="http://www.google.com/recaptcha/api.js?render=recaptchaSiteKey"></script>
<script>
grecaptcha.ready(function() {
grecaptcha.execute('recaptchaSiteKey', {action: 'homepage'}).then(function(token) {
$.ajax({
//pass the toket to Webmethod using Ajax
});
});
});
</script>
Reference link:
https://developers.google.com/recaptcha/docs/verify
https://developers.google.com/recaptcha/docs/display#js_api
Now in the aspx.cs you need to write a "[WebMethod]" to receive the token from Ajax request .
[WebMethod]
public static void CaptchaVerify(string token)
{
var responseString = RecaptchaVerify(token);
ResponseToken response = new ResponseToken();
response = Newtonsoft.Json.JsonConvert.DeserializeObject<ResponseToken>(responseString.Result);
}
To get the response from google recapcha api u need to use async call using httpClient . you also need to create a class which will contain same properties like the response string . After getting the "responseString" u need to convert the response to ResponseToken object by using Newtonsoft.Json.
response = Newtonsoft.Json.JsonConvert.DeserializeObject<ResponseToken>(responseString.Result);
private string apiAddress = "https://www.google.com/recaptcha/api/siteverify";
private string recaptchaSecret = googleRecaptchaSecret;
public async Task<string> RecaptchaVerify(string recaptchaToken)
{
string url = $"{apiAddress}?secret={recaptchaSecret}&response={recaptchaToken}";
using (var httpClient = new HttpClient())
{
try
{
string responseString= httpClient.GetStringAsync(url).Result;
return responseString;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
}
public class ResponseToken
{
public DateTime challenge_ts { get; set; }
public float score { get; set; }
public List<string> ErrorCodes { get; set; }
public bool Success { get; set; }
public string hostname { get; set; }
}
The accepted answer on this page is totally wrong!!! Google returns a score between 0 and 1 to indicate whether the submission is likely to be a bot or likely to be a human.
The success property returned only means that the recaptcha token was processed correctly.
It is the score property that should be checked, not the success property
These lines are the probelem
if (JSONdata.success != "true")
return false;
return true;
The actual score to compare will probably be in a variable that can be adjusted if need be. Google recommends starting with 0.5.
So the code should change to something like:
var recaptchaScore = 0.5m; // this could be in appSettings or whereever/however you are storing your constants
if (JSONdata.success != "true" || JSONdata.score <= recaptchaScore)
return false;
return true;
Of course you will likely want to add logging etc to this answer but this is the bare logic that is required.
The accepted answer isn't following the Google's spec for sending the response and checking the action. Its Http requests will exhaust the number of sockets also. This is my implementation.
Browser
// Could be called from an event or another piece of code.
function FunctionToCall(term) {
// Google reCaptcha check
grecaptcha.ready(function() {
grecaptcha.execute(reCaptchaSiteKey, {action: "search"}).then(function(token) {
// You can take the response token Google returns, check it server side using
// the GoogleReCaptcha class and respond with a pass or fail. If a pass, run a block of code client side.
// { ... block of code ... }
// Or if you want to secure an endpoint that your sending request too.
// Send the response token with the request to your endpoint and check the response token server side and respond with a pass or fail.
// Use the repsonse to show a message or redirect site, etc
});
});
}
Server
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
public class GoogleReCaptcha
{
public class ReCaptchaResponse
{
public bool success { get; set; }
public double score { get; set; }
public string action { get; set; }
public DateTime challenge_ts { get; set; }
public string hostname { get; set; }
[JsonProperty("error-codes")]
public List<string> error_codes { get; set; }
}
public static async Task<(ReCaptchaResponse Response, bool HasPassed)> ReCaptchaPassed(string secretKey, string gRecaptchaToken, string expected_action)
{
try
{
// validate
if (string.IsNullOrWhiteSpace(secretKey) || string.IsNullOrWhiteSpace(gRecaptchaToken) || string.IsNullOrWhiteSpace(expected_action))
return (null, false);
// we use HttpClientFactory to avoid exhausting number of sockets available
var httpClient = HttpClientFactory.Create();
var verifyUrl = "https://www.google.com/recaptcha/api/siteverify";
var parameters = new Dictionary<string, string>
{
{"secret", secretKey},
{"response", gRecaptchaToken}
//{"remoteip", "ip" } <= this is optional
};
using (HttpContent formContent = new FormUrlEncodedContent(parameters))
{
using (var response = await httpClient.PostAsync(verifyUrl, formContent).ConfigureAwait(false))
{
// check HTTP response code
if (response.StatusCode != HttpStatusCode.OK)
return (null, false);
// get reCaptcha response
string gRecaptchaJsonresult = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (string.IsNullOrWhiteSpace(gRecaptchaJsonresult))
return (null, false);
// check reCaptcha response is successful
var recaptcha_response = JsonConvert.DeserializeObject<ReCaptchaResponse>(gRecaptchaJsonresult);
if (recaptcha_response == null)
{
//Logging.Log(new Logging.LogItem { Msg = $"Google RecCaptcha response is null" }, DefaultLogValues);
return (recaptcha_response, false);
}
if (!recaptcha_response.success)
{
var errors = string.Join(",", recaptcha_response.error_codes);
//Logging.Log(new Logging.LogItem { Msg = $"Google RecCaptcha error codes:\n{errors}" }, DefaultLogValues);
return (recaptcha_response, false);
}
// check reCaptcha response action
if (recaptcha_response.action.ToUpper() != expected_action.ToUpper())
{
//Logging.Log(new Logging.LogItem { Msg = $"Google RecCaptcha action doesn't match:\nExpected action: {expected_action} Given action: {recaptcha_response.action}" }, DefaultLogValues);
return (recaptcha_response, false);
}
// response score
// anything less than 0.5 is a bot
if (recaptcha_response.score < 0.5)
return (recaptcha_response, false);
else
return (recaptcha_response, true);
}
}
}
catch (Exception ex)
{
//Logging.Log(ex, DefaultLogValues);
// default to false
return (null, false);
}
}
}
You would call it like so..
var reCaptchaTask = GoogleReCaptcha.ReCaptchaPassed(Settings.GoogleReCaptcha.secret_key, SearchReq.gRecaptchaToken, "search");
Make sure to put your keys in a settings file and not in the code.
There are several Recaptcha libraries available for ASP.Net. I chose to use reCAPTCHA.AspNetCore because it provides an HtmlHelper.
Please note that this library only supports one ReCatpcha per page, and it doesn't support Recaptcha v3 passive monitoring on non-form pages.
I want to know exactly why this is not working:
[HttpPost]
public IHttpActionResult Post(Slack_Webhook json)
{
return Ok(json.challenge);
}
public class Slack_Webhook
{
public string type { get; set; }
public string token { get; set; }
public string challenge { get; set; }
}
The Official Documentation says:
We’ll send HTTP POST requests to this URL when events occur. As soon
as you enter a URL, we’ll send a request with a challenge parameter,
and your endpoint must respond with the challenge value.
This is an example object (JSON) sent by Slack:
{
"token": "Jhj5dZrVaK7ZwHHjRyZWjbDl",
"challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P",
"type": "url_verification"
}
EDIT:
I could write a book on code that does not work in this issue... here's another example that did not work - still no idea what is wrong:
[HttpPost]
public IHttpActionResult Post()
{
var pairs = Request.GetQueryNameValuePairs();
bool isValidToken = false;
string c = "This does not work.";
foreach(var pair in pairs)
{
if (pair.Key == "token")
{
if (pair.Value == "<UNIQUETOKEN>")
{
isValidToken = true;
}
}
if (pair.Key == "challenge")
{
c = pair.Value;
}
}
if (isValidToken == true)
{
return Json(new {challenge = c });
}
else
{
return BadRequest();
}
}
EDIT2:
Very interesting that I get NULL as a response from below code - that means the body of the received POST is empty.. Could anyone with a working Slack-Integration try that out? So their site is wrong, stating the challenge is sent in the body - where else could it be?
// POST: api/Slack
[HttpPost]
public IHttpActionResult Post([FromBody]string json)
{
return Json(json);
}
EDIT3:
This function is used to get the raw request, but there is nothing inside the body - I am out of solutions.. the support of Slack said, they have no idea about ASP.NET and I should ask here on SO for a solution. Here we are again! ;-)
[HttpPost]
public async Task<IHttpActionResult> ReceivePostAsync()
{
string rawpostdata = await RawContentReader.Read(this.Request);
return Json(new StringContent( rawpostdata));
}
public class RawContentReader
{
public static async Task<string> Read(HttpRequestMessage req)
{
using (var contentStream = await req.Content.ReadAsStreamAsync())
{
contentStream.Seek(0, SeekOrigin.Begin);
using (var sr = new StreamReader(contentStream))
{
return sr.ReadToEnd();
}
}
}
}
The result ( as expected ) looks like this:
Our Request:
POST
"body": {
"type": "url_verification",
"token": "<token>",
"challenge": "<challenge>"
}
Your Response:
"code": 200
"error": "challenge_failed"
"body": {
{"Headers":[{"Key":"Content-Type","Value":["text/plain; charset=utf-8"]}]}
}
I think I'm missing something - is there another way to get the body of the POST-Request? I mean, I can get everything else - except the body ( or it says it is empty).
EDIT4:
I tried to read the body with another function I found - without success, returns empty string - but to let you know what I already tried, here it is:
[HttpPost]
public IHttpActionResult ReceivePost()
{
var bodyStream = new
StreamReader(HttpContext.Current.Request.InputStream);
bodyStream.BaseStream.Seek(0, SeekOrigin.Begin);
var bodyText = bodyStream.ReadToEnd();
return Json(bodyText);
}
While trying to solve this I learnt a lot - but this one seems to be so impossible, that I think I will never solve it alone. Thousands of tries with thousands of different functions - I have tried hundreds of parameters and functions in all of WebApi / ASP.NET / MVC / whatever - why is there no BODY? Does it exist? What's his/her name? Where does it live? I really wanna hang out with that parameter if I ever find it, must be hidden at the end of the rainbow under a pot of gold.
If you can use ASP.NET Core 2, this will do the trick:
public async Task<ActionResult> HandleEvent([FromBody] dynamic data)
=> new ContentResult {Content = data.challenge};
According to the official documentation linked to in the OP you have to format your response depending on the content type you return.
It is possible you are not returning the value (challenge) in one of the expected formats.
Once you receive the event, respond in plaintext with the challenge
attribute value. In this example, that might be:
HTTP 200 OK
Content-type: text/plain
3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P
To do the above you would have needed to return your request differently
[HttpPost]
public IHttpActionResult Post([FromBody]Slack_Webhook json) {
//Please verify that the token value found in the payload
//matches your application's configured Slack token.
if (ModelState.IsValid && json != null && ValidToken(json.token)) {
var response = Request.CreateResponse(HttpStatusCode.OK, json.challenge, "text/plain");
return ResponseMessage(response);
}
return BadRequest();
}
Documentation also shows
Or even JSON:
HTTP 200 OK
Content-type: application/json
{"challenge":"3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P"}
Which again would have to be formatted a little differently
[HttpPost]
public IHttpActionResult Post([FromBody]Slack_Webhook json) {
//Please verify that the token value found in the payload
//matches your application's configured Slack token.
if (ModelState.IsValid && json != null && ValidToken(json.token)) {
var model = new { challenge = json.challenge };
return Ok(model);
}
return BadRequest();
}
Here's how you can access the data:
[HttpPost]
[Route("something")]
public JsonResult DoSomething()
{
var token = HttpContext.Request.Form["token"];
// Is the same as:
// var token = Request.Form["token"];
return new JsonResult(token);
}
I suggest using a Request Bin for further debugging.
this opportunity Ii'd like to thank everyone who has an answer to this question, I'm trying to get a json from my web api service and I can't this is my code at the web api...
[ResponseType(typeof(List<CompanyType>))]
[Route("GetList")]
[DeflateCompression]
public async Task<IHttpActionResult> Get()
{
List<CompanyType> companyTypes = (List<CompanyType>)MemoryCacheManager.GetValue(#"CompanyTypes");
if (companyTypes != null) return Ok(companyTypes);
companyTypes = await _CompanyType.Queryable().ToListAsync();
if (companyTypes == null) return Ok(HttpStatusCode.NoContent);
MemoryCacheManager.Add(#"CompanyTypes", companyTypes);
return Ok(companyTypes);
}
and at the site of my client I got this
public async Task<T> GetAsync<T>(string action, string authToken = null)
{
using (var client = new HttpClient())
{
if (!authToken.IsNullOrWhiteSpace())
client.DefaultRequestHeaders.Authorization = AuthenticationHeaderValue.Parse(#"Bearer " + authToken);
var result = await client.GetAsync(BuildActionUri(action));
string json = await result.Content.ReadAsStringAsync();
if (result.IsSuccessStatusCode)
return JsonConvert.DeserializeObject<T>(json); //This line fails because the characters in the value
throw new ApiException(result.StatusCode, json);
}
}
As you can see there nothing than weird here it is a simple code that try to parse a json value to a Generic class but this fails bacause when i call my webapi Url it gives me this value
json = ��VR�LQ�R2T�Q�2u�B*R�"E�e�)�#q�������̔Ԣb%��Ҝ�Z�>#�>#�>�̊B������J�r2�q�
I don't know why my webapi give me tha value, when I try to debug just my service it give me this value
<ArrayOfCompanyType xmlns:i="http://www.w3.org/2001/XMLSchema-instance" ><CompanyType z:Id="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"><Id>1</Id><Type>Privada</Type><JobProviders i:nil="true" /></CompanyType><CompanyType z:Id="i2" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"><Id>2</Id><Type>Mixta</Type><JobProviders i:nil="true" /></CompanyType><CompanyType z:Id="i3" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"><Id>3</Id><Type>Publica</Type><JobProviders i:nil="true" /></CompanyType></ArrayOfCompanyType>
as you can see everything looks fine but the problem start when I try to parse to get this value from my client.
this is my class
[DataContract(IsReference = true, Name = #"CompanyType", )]
public class CompanyType : Entity
{
[DataMember(Order = 0)]
public int Id { get; set; }
[DataMember(Order = 1)]
public string Type { get; set; }
[DataMember(Order = 2)]
public virtual List<JobProvider> JobProviders { get; set; }
}
I tried it without de DataContracts and still the same error.
best regards!.
Well I figured out, I was trying to use this sample http://blog.developers.ba/asp-net-web-api-gzip-compression-actionfilter/ but the thing was that the serializer wasn´t registered, so at my startup project I did this
GlobalConfiguration.Configuration.Formatters.Add(new ProtoBufFormatter());
And I changed my Actions deleting the attribute [DeflateCompression]
[ResponseType(typeof(List<CompanyType>))]
[Route("GetList")]
//[DeflateCompression]
public async Task<IHttpActionResult> Get()
{
Logic goes here....
}
And It's working now, but now I have another Issue and its when I try to make a call to my webapi action where I have to response an IHttpActionResult there is an exception of
no serializer defined for type: System.Object
I have the following controller action using the web api on a .net 4.0 web forms web application.
public dynamic Post(Guid id, string adminNotes = "", string artNotes = "")
{
dynamic response = new ExpandoObject();
response.Success = false;
Udac udac = CustomerUdacs.Where(x => x.EditKey == id).FirstOrDefault();
if (udac != null)
{
udac.AdminNotes = adminNotes.Trim();
udac.ArtNotes = artNotes.Trim();
response.Success = true;
}
return response;
}
I'm using jQuery ajax() to post the data through. I am using a Guid as my id (which is stored in ajax_edit_key in my javascript). When I use this:
$.ajax({
type: "POST",
url: "/api/notes/"+ajax_edit_key,
data: { adminNotes: $("#tbEditNotesAdmin").val(), artNotes: $("#tbEditNotesArt").val() }
}).done(function (data) {
if (data.Success) {
$("#tbEditNotesAdmin").val(''); //td.id-notes-admin
$("#tbEditNotesArt").val(''); //td.id-notes-art
ajax_edit_key = '';
$dialog.dialog("close");
}
}).fail(function () {
alert('fail');
});
it calls the action but my adminNotes and artNotes are passing through from the browser as empty strings.
If I change the url to include the parameters in the querystring it works fine.
url: "/api/notes/"+ajax_edit_key+"?"+ "adminNotes="+$('#tbEditNotesAdmin').val()+"&artNotes="+$('#tbEditNotesArt').val()
//data: { adminNotes: $("#tbEditNotesAdmin").val(), artNotes: $("#tbEditNotesArt").val() }
Why is this? How can I get it to use the data parameter
The problem here is the way how WebAPI engine parses multiple parameters. It can parse only one parameter, which comes from body request by default, and you have two.
The solution would be:
To create your own model binder (this article would help you: http://blogs.msdn.com/b/jmstall/archive/2012/04/18/mvc-style-parameter-binding-for-webapi.aspx)
To create a separate model class that will contain all your passing parameters (which is easier to me).
For the second option you need simply to create the model:
public class NotesModel
{
public string AdminNotes { get; set; }
public string ArtNotes { get; set; }
}
And change signature of your action to:
public dynamic Post(Guid id, NotesModel model)
And you don't need to change your JS.