Post request with query string parameters - c#

I'm trying to build a Web API for a complex type of searching. I want to support paging in the results. The "state" of the search is complex, so not really suitable for persisting in the query string. But I'd like for the paging options to be included within the query string.
I've implemented two methods, as below, and the web api code seems to understand what I'm trying to do, but the query string parameters never get assigned. Any hints or advice on this would be appreciated:
public Task<HttpResponseMessage<SearchResults>> Post(SearchRequest request) //Method 1
{
return Post(request, null, null);
}
public async Task<HttpResponseMessage<SearchResults>> Post(SearchRequest request, string page, string pageSize) //Method 2
{
//All of the complex code, including...
if (PageNo < TotalPages)
{
searchResults.AddLink(new Link { Uri = Url.Route("DefaultApi", new {
controller = "AdvancedSearch",
page = (PageNo + 1).ToString(),
pageSize = PageSize.ToString() }),
Relation = "nextPost" });
}
//Final wrap up, etc
}
On POSTing a SearchRequest to /api/AdvancedSearch, Method 1 is called, which in turn calls Method 2, which does the search, and packages up the results. As you can hopefully see, included in this result (if more pages of results are available) is a URL to post to for the next page. The generated URL base on this is /api/AdvancedSearch?page=2&pageSize=20, exactly as I'd hoped.
In my calling code, I then perform a POST to this second URL. Only Method 2 is invoked (as expected). But, both page and pageSize are null.
What am I doing wrong? Or what else do you need to see in order to answer this question?

Below is not needed
You need to decorate your parameters using [FromUri]:
public async Task<HttpResponseMessage<SearchResults>> Post(SearchRequest request,
[FromUri]string page,
[FromUri]string pageSize)
As I said in the comments, HttpResponseMessage<T> is being dropped since the Content property of HttpResponseMessage will perform all needed operations.
I checked and I passed querystring params in a post, no problem.

Related

How can I make a return with parameters in a View c# asp .net mvc?

Sorry for the title, but don't know how to explain it. (.NET ASP MVC)
So what I'm trying is to create a payment request via TripleA API(redirect on their page), if the payment is successful, they will redirect on my success page with some parameters, how can I handle those parameters?
What I've tried:
public IActionResult ErrorPage(string payment_reference, string status)
{
return View(payment_reference,status);
}
https://developers.triple-a.io/docs/triplea-api-doc/dd286311a5afc-make-a-payment-request
(scroll down to success_url for more info)
To expand on Steve's comment, create a record (less code than a class) as follows...
public record ErrorViewModel(string PaymentReference, string Status);
...then use this when you send data to the view...
public IActionResult ErrorPage(string payment_reference, string status)
{
return View(new ErrorViewModel(payment_reference,status));
}
You'll need to update your view to have the following line at the top...
#model ErrorViewModel
That should be all you need.
Based on the documentation, you expect a request like this,
https://www.myshop.com/payment-success?status=paid&payment_reference=ASDDF...&order_currency=USD&order_amount=10
And you translate that into a controller method,
[HttpGet("payment-success")]
public IActionResult ResultPage(string payment_reference, string status, string order_currency, decimal order_amount)
{
var result = new ResultViewModel(payment_reference,status, order_currency, order_amount);
return View(result);
}
I also noticed that the doc says,
Note: This field is required if integrating using External URL Payment Form. For other integrations, either insert the field with a url, or remove the field completely.
So if you use External URL Payment Form integration, then I don't think you will be able to get the status and reference.
The same applies for cancel_url.

How does the result filter work in ASP.NET Core?

Can someone explain the difference between the Action Filter and the Result Filter in ASP.NET Core MVC? I really didn't get it reading the documentation. What exactly is the result execution that we see in the diagram here (gray box on the very bottom):
In the documentation it says that
Action filters can change the result returned from the action.
So if it already changes the result why do we need an Result filter?
According to Microsoft Docs:
Action filters:
Run code immediately before and after an action method is called.
Can change the arguments passed into an action.
Can change the result returned from the action.
Are not supported in Razor Pages.
But, the ResultFilters have a bit difference in executaion:
Result filters run code immediately before and after the execution of action results. They run only when the action method has executed successfully. They are useful for logic that must surround view or formatter execution.
Consider you want to return an API response to the client for a User model with lots of properties. You can simply create a response based on the API model contract like this:
public class UserDetailFilter : ResultFilterAttribute
{
public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
var result = context.Result as ObjectResult;
if (result?.Value is UserResponse value)
result.Value = new
{
Id = value.Id,
Username = value.Username,
Fullname = value.Fullname,
Mobile = value.Mobile,
Email = value.Email,
UpdatedAt = value.UpdatedAt
};
await next();
}
}

Getting POST data from WebAPI

We're working on developing an application that uses Plivo for sending and receiving SMS messages. For every request that Plivo sends, they also send a signature in the HTTP header so that we can verify the request came from Plivo and not from a random user.
https://www.plivo.com/docs/xml/request/#validation
To do this validation, we require the POST content as a query string (eg: To=15555555555&From=11234567890&TotalRate=0&Units=1&Text=Text!&TotalAmount=0&Type=sms&MessageUUID=2be622bc-79f8-11e6-8dc0-06435fceaad7).
Current solution
This is what we have so far:
private bool VerifyPlivo(object thing, HttpRequestMessage Request)
{
if (Request.Headers.Contains("X-Plivo-Signature"))
{
Dictionary<string, string> reqParams = (from x in thing.GetType().GetProperties() select x).ToDictionary(x => x.Name, x => (x.GetGetMethod().Invoke(thing, null) == null ? "" : x.GetGetMethod().Invoke(thing, null).ToString()));
IEnumerable<string> headerValues = Request.Headers.GetValues("X-Plivo-Signature");
string signature = headerValues.FirstOrDefault();
return XPlivoSignature.Verify(Request.RequestUri.ToString(), reqParams, signature, plivoToken);
}
else
{
return false;
}
}
[Route("RecieveSMS")]
[HttpPost]
public HttpResponseMessage RecieveSMS(PlivoRecieveSMS req)
{
if (!VerifyPlivo(req, Request))
{
return new HttpResponseMessage(HttpStatusCode.Forbidden);
}
... // do actual work here
}
This works by using the object that it maps to PlivoRecieveSMS and doing some reflection to get the properties and values, and sticking them in a Dictionary. This works well especially given our lack of the preferred solution...
Preferred solution
Right now, we require a model (PlivoRecieveSMS) to map the data, and then do introspection to find the key/values. We would like to move the logic to an extension of System.Web.Http.AuthorizeAttribute, so that we can do something as simple as:
[AuthorizedPlivoApi]
[Route("RecieveSMS")]
[HttpPost]
public HttpResponseMessage RecieveSMS(PlivoRecieveSMS req)
{
... // do actual work here
}
The actual authorization is done in AuthorizedPlivoApi - if it's not valid, the request never reaches the controller. But we cannot do this at the moment because we can't map it to a specific object inside of AuthorizedPlivoApi.
I would like to access the POST key's / values directly, or perhaps map it to a dynamic object that isn't pre-defined before hand. If I can do that, we can then achieve our preferred solution.
tl;dr: is there any way to push application/x-www-form-urlencoded data from a POST request into a Dictionary<string,string>() without using a specific model?

How to use parameters as filters in MVC?

I think this is a simple question, but I somehow cannot sort it out. I have a List < SomeClass > that will be returned by an MVC controller. But, I want to filter the results server side. So suppose class is like:
public SomeClass()
{
string option1;
string option2;
int indexing;
}
Now I want to do a GET request, but the results need to be filtered on option1. So I can query the database properly. So I tried to jsonconvert.serialize an instance of the class with option1 set to 'something', but how can I deliver this to my MVC GET method? With httpclient there is no content, with httpWebRequest and writing it into a stream I have the error 'no content can be send with this verb', where verb is set to GET.
I think I am missing a basic thing here. Can anyone point me in the right direction?
if you want to keep your action as a GET, you need to call the action with the right querystring paramters i.e. /ActionName?option1=somevalue&option2=othervalue
and your action:
[HttpGet]
public ActionResult ActionName(SomeClass someclass)
or post the json option and chance your HttpGetverb to HttpPost
That's simple, you can use Json Result:
https://msdn.microsoft.com/en-us/library/system.web.mvc.jsonresult(v=vs.118).aspx
[HttpGet]
public ActionResult GetListObjects(string filter)
{
//getdata items
var objects =
from item in items
where (string)item.option1 == filter
select item;
return Json(objects, JsonRequestBehavior.AllowGet);
}

TempData[] getting wiped despite no requests taking place

TempData is supposed to persist for a subsequent request. However when I check the TempData in a subsequent controller I get a null. Why is TempData[] getting wiped off. Here are my two controllers. I am calling them in succession. So TempData[] should persist from one request to the next. Here is code from controller 1:
[HttpGet]
public ActionResult EditCampaign(int? Id)
{
ViewBag.Banner = bannerText.Replace(" ", " ");
// This is passed in case we need to add a new product or edit one. Then we'll
// need the campaign id for reference purposes.
TempData["campaign_id"] = Id;
TempData["campaignBanner"] = bannerText.Replace(" ", " ");
ViewBag.StartDate = debugger.startDate.ToShortDateString();
ViewBag.EndDate = debugger.endDate.ToShortDateString();
int Id1 = Convert.ToInt32(TempData["campaign_id"]);
int convertedId1 = Id1
Here is where I try to get the value in Controller 2:
[HttpPost]
public ActionResult EditCampaign(CampaignDTO camps)
{
// Do this up top. i.e. get the campaign ID
camps.Id = Convert.ToInt32(TempData["campaign_id"]);
string success = "";
I suspect that assigning the value of TempData in the penultimate line of controller 1 might be wiping off the data. If thats the case that is something new and not documented. Please help.
Reading the data is enough to remove it. Here's the relevant source:
public object this[string key]
{
get
{
object value;
if (TryGetValue(key, out value))
{
_initialKeys.Remove(key);
return value;
}
return null;
}
set
{
_data[key] = value;
_initialKeys.Add(key);
}
}
So in controller 1, when you say:
int Id1 = Convert.ToInt32(TempData["campaign_id"]);
you are actually removing the data you just inserted.
There are many ways to work around this, but if you must read it from TempData, use Peek() instead.
You have some flawed info. The data stored in the TempData property persists for only one request.
http://msdn.microsoft.com/en-us/library/system.web.mvc.viewpage.tempdata%28v=vs.118%29.aspx
TempData is useful when you are redirecting (HTTP 302 or 303, i.e. RedirectToAction in MVC) to pass along some context. It does not persist across separate HTTP requests. Based on your code sample, it suggests your client code first makes a GET to controller one, then issues a second request to controller two.
Your best bet is probably to return the necessary data as part of your response in controller one, then make that part of the incoming request to controller. You could potentially also use Session variables, https://code.msdn.microsoft.com/How-to-create-and-access-447ada98.

Categories

Resources