I have two methods on a web service that I am trying to invoke with WebClient:
[Route("TestDownload")]
[HttpGet]
public string TestDownload()
{
return "downloaded";
}
[Route("TestUpload")]
[HttpPost]
public string TestUpload(string uploaded)
{
return uploaded;
}
This code works:
using (var wc = new WebClient())
{
var sResult = wc.DownloadString("http://localhost/Website/TestDownload");
Console.WriteLine(sResult);
}
This code throws a System.Net.WebException: (404) Not Found
using (var wc = new WebClient())
{
var sResult = wc.UploadString("http://localhost/Website/TestUpload", "test");
Console.WriteLine(sResult);
}
What am I doing wrong? Thanks
try adding a routing for that controller/method, something like this:
routes.MapRoute(
"yourRouteName", // Route name
"{controller}/{action}",
new { controller = "yourController", action = "TestUpload", uploaded="" } // Parameter defaults
);
I think I figured it out. The UploadString on WebClient is using the string parameter as the http request body. By default, WebApi supplies controller method parameters for simple types, including string, from the query string (see https://learn.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api). To override this behavior and indicate that a string parameter is to be found in the request body, you use the [FromBody] attribute.
[Route("TestUpload")]
[HttpPost]
public string TestUpload([FromBody] string uploaded)
{
return uploaded;
}
Related
If I have a controller with HTTP POST action with once or several parameters like this:
//[HttpPost]
public ActionResult Ajaxbuscarope(string texto="")
{
}
How could I access to "texto" parameter directly from the controller Initialization...
protected override void Initialize(System.Web.Routing.RequestContext
requestContext)
{
var texto=???
}
I can access the Get parameters using this...
var url_with_params=System.Web.HttpContext.Current.Request.Url.AbsoluteUri;
But this is not working with post request with declared parameters
System.Collections.Specialized.NameValueCollection post = System.Web.HttpContext.Current.Request.Form;
HttpRequest request = HttpContext.Current.Request;
request.InputStream.Seek(0, SeekOrigin.Begin);
var reader = new StreamReader(request.InputStream);
var requestFromPost = Encoding.Default.GetString(HttpContext.Current.Request.BinaryRead(HttpContext.Current.Request.TotalBytes));
//this is very important to have the parameters available in the action
request.InputStream.Seek(0, SeekOrigin.Begin);
I can't for the life of me get this to work. I keep getting 404.
Here's the WebApi2 code:
[HttpPost]
public IHttpActionResult Post(string testString)
{
if(!string.IsNullOrEmpty(testString))
{
return Ok(testString);
}
else
{
return BadRequest();
}
}
Here's the WebClient code:
public async Task PostingToWebServiceShouldWork()
{
var apiEndPoint = new Uri(String.Format("{0}/Paging", ConfigurationManager.AppSettings["ApiEndpoint"].ToString()));
var apiRoot = new Uri(apiEndPoint.GetLeftPart(UriPartial.Authority));
var apiCall = apiEndPoint.PathAndQuery.Substring(1, apiEndPoint.PathAndQuery.Length - 1);
using (var client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true }))
{
client.BaseAddress = apiRoot;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpContent content = new StringContent("testSTring");
HttpResponseMessage response = await client.PostAsync(apiCall, content);
if(response.IsSuccessStatusCode)
{
}
}
}
I just want to post a simple string to the web service. This should be dead simple, and it's giving me a migraine, lol. I've tried everything I can think of, and I have to be missing some tiny detail...
Thanks!
Because your API endpoint is simply a string instead of an object, WebAPI is looking for that string as a query string parameter. You have two options:
Use the [FromBody] attribute in your action's definition
public IHttpActionResult Post([FromBody] string testString)
Send the string on the URL instead of in the body (works, but if you're going for security over HTTPS this exposes what you were posting)
See http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api for a deeper explanation and examples
IDE: Visual Studio 2012
I have controller as follows:
public class MyController: ApiController
{
public IHttpActionResult AddMyControllerInfo([FromBody]Dictionary<string, string> dictCustomer)
{
//Some logic...
return Ok("Success");
}
}
And it is being called from client project:
Calling code is as follows:
internal static void SendInfoToMyController(Dictionary<string, string> dictCustomer)
{
string jsDict = Utilities.SerializeToJson<Dictionary<string, string>>(dictCustomer);
string js = Utilities.MakeRequest_Post("/api/AddMyControllerInfo", jsDict);
}
and here is Make request function:
internal static string MakeRequest_Post(string sURL, string formData)
{
try
{
sURL = ConfigurationManager.AppSettings["ServerApiPath"] + sURL;
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
var result = client.UploadString(sURL, "POST", "=" + formData);
}
}
catch (Exception ex)
{
}
return "";
}
Above code is working fine when I receive the [FromBody] parameter data in the form of string (json format) datatype, and deserialize it to dictionary form.
but in above scenario I am receiving dictionary object as null.
Can you tell me how to receive the complex object at web api, for above scenario.
You are using the wrong content type in your requests. In your MakeRequest_Post method, change the content type header as follows:
client.Headers[HttpRequestHeader.ContentType] = "application/json";
I believe you also need to remove the leading = from the POST body like this:
var result = client.UploadString(sURL, "POST", formData);
Question Background:
I have a basic WebApi project hosted as a WebApp in Azure.
The Issue:
The problem I have is If I access any method other than a 'GET' type then I'm receiving the following error in my JSON response:
The requested resource does not support http method 'GET'
The Code:
The following code is how the project currently is.
RouteConfig.cs class:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Home",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
The ValuesController controller class:
public class ValuesController : ApiController
{
private List<CompanyData> _company;
public ValuesController()
{
_company = new List<CompanyData>
{
new CompanyData
{
CompanyName = "SmallTech.Ltd",
CompanyOwner = "John Smith",
CompanyIndustry = "Electronic Components",
EmployeeNo = "3"
}
};
}
public List<CompanyData> GetCompanyData()
{
return _company;
}
//GET api/values
public IEnumerable<string> Get()
{
return new string[] { "Test GET Method"};
}
// GET api/values/5
public string Get(int id)
{
return "value";
}
// POST api/values
public void Post(string value)
{
string test = value;
}
// PUT api/values/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/values/5
[HttpDelete]
public void Delete(int id)
{
}
An example of calling the above Delete method when the error occurs is:
http://testwebapisite.azurewebsites.net/api/values/Delete/5
I have read other people having the same issue and using the HTTP attributes from the System.Net.MVC. I can confirm I'm not using this and am using `System.Net.Http.HttpPostAttribute.
Any help working out why I'm receiving the GET error message would be great.
You are trying to access an action which clearly specifies delete as its verb via a GET request.
By default the browser will do a GET request if you paste a url so thats pretty much easy to test but for the other verbs you'll have to use an actual rest/http client to specify the verb. You can use Postman or Rest Console if you use chrome to dev/test
In addition to those tools, you might want to have fiddler installed .. it will help you track all http activity (both sent/received) you'll know exactly what you are sending and receiving from the wire
You could also do this from code if you want using HttpClient.
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://testwebapisite.azurewebsites.net/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.DeleteAsync("api/values/5");
}
You haven't shown the code that you are using to invoke the API, but I suspect you are not using the DELETE HTTP verb. The resource you are accessing has URI or http://testwebapisite.azurewebsites.net/api/values/5 - note the action name is not specified. Rather, as the comment of your method suggests, you should be using the DELETE HTTP verb. Example:
using (var client = new HttpClient())
await client.DeleteAsync("http://testwebapisite.azurewebsites.net/api/values/5");
I am consuming a web api wrote in c#, MVC, that looks like:
public IEnumerable<Day> Post([FromBody] string postObject)
Using fiddler or poster I can post to that REST service since my body has a = before my sending JSON, something like
={"BillTypeId":"4","RestId":"1"}
Using retrofit to make this call I can not send that initial = and my request looks like
{"BillTypeId":"4","RestId":"1"}
That makes the rest service receive always a null parameter.
Do you know a way to send it before my json? Since I am calling that rest like this
void postToGetDayList(#Body ResquestListenerBillType request, Callback<List<Day>> callback);
Thank you!!!
If you haven't fixed your issue, I think you can refer to my following code:
WebAPI:
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// POST api/values
public string Post([FromBody]string value)
{
return value;
}
}
Retrofit WebAPIService:
public interface WebAPIService {
#GET("/api/values")
List<String> listValues();
#POST("/api/values")
String postValues(#Body String value);
}
Call webAPIService.postValues("BNK");
You will find the result as the following image. Hope this helps!
before send class convert to string and add one " fist string and add one " on last string then send body
my client API is :
[Put("/WebPage/{key}/")]
Task<string> PutWebPage([AliasAs("key")]string id, [Body]string value);
sample code is :
WebPageModel webPageModelSave = new WebPageModel();
webPageModelSave = ObjectCopier.CloneClass(Public.CashEntity.webPageModel);
webPageModelSave.Address = uxLabel_AddressTitle.Text;
string codeingData = JsonConvert.SerializeObject(webPageModelSave);
codeingData = ArmanSerialize.CryptoString.Encrypt(codeingData, "5552552");
string resutlt = await Public.Helper.ApiServer.PutWebPage("123", "\""+codeingData+"\"");
and on server remove the " fist and last string like this:
// PUT api/<controller>/5
[HttpPut("{id}/")]
public string Put(string id, [FromBody]string value)
{
string removeCotation = value.Remove(value.Length - 1, 1).Remove(0, 1);
string valueItem = ArmanSerialize.CryptoString.Decrypt(value, "5552552");
string baseUrl = Request.Host.Host;
baseUrl = baseUrl.ToLower().Replace("http://", "").Replace("https://", "");
var serverID = 123;
if (id.Replace("\"", "") == serverID.Replace("\"","") && !string.IsNullOrEmpty(valueItem))
{
WebPageModel webPageModel = new WebPageModel();
webPageModel = JsonConvert.DeserializeObject<WebPageModel>(valueItem);
EntityFrameworkCore.LogicLayer logicLayer = new EntityFrameworkCore.LogicLayer();
logicLayer.UpdateWebPageModel(webPageModel);
return JsonConvert.SerializeObject("OK");
}
else
{
//error
return JsonConvert.SerializeObject("Error");
}
}
I test it on xamarin form and asp.net core 3 its work it.