C# MVC Access Action Param from controller Initialization - c#

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);

Related

How to read request body in OnActionExecuting(ActionExecutingContext context) in IActionFilter Asp.net core

I am sending AES encrypted request body to controller following is a sample:
(using crypto-js)
{body: "U2FsdGVk186Jj7LySqT966qTdpQZwiR+wR0GjYqBzR4ouFAqP8Dz8UPPTv"}
I have created action filter, so whenever the request is posted I can decrypt the request in action filter than pass the decrypted request to the desired controller.
request after decryption :
{Name: "admin123" }
so how to get encrypted request body in action filter? and how to pass decrypted request body to the controller
I have tried WEB API in ASP.NET core StreamReader but it is returning an empty string
I want to pass decrypted request body to the controller
filter
public void OnActionExecuting(ActionExecutingContext context)
{
var req = context.HttpContext.Request;
using (StreamReader reader = new StreamReader(req.Body, Encoding.UTF8, true, 1024, true))
{
bodyStr = reader.ReadToEnd();
}
req.Body.Position = 0;
}
controller
[HttpPost("[action]")]
public async Task<string> MyControllerName(InfoReq info)
{
}
class
public class InfoReq
{
public string Name{ get; set; }
}
You can use :
var body = context.ActionArguments["info"] as InfoReq ;
Here you need to go for the middleware approach.Read the documentation Middleware
if you want to read stream you must have to request.EnableRewind().because of Request. body is a read and forward only stream that doesn't support reading the stream a second time.
request.EnableRewind();
after reading apply your logic and after that the request you need to add original stream back on the Response. Body
public void OnActionExecuting(ActionExecutingContext context)
{
var request = context.HttpContext.Request;
try
{
request.EnableRewind();
using (StreamReader reader = new StreamReader(request.Body))
{
return reader.ReadToEnd();
}
}
finally
{
request.Body = request;
}
context.Request.Body.Position = 0
}
You should have to set stream position zero(0)
request.Body.Position = 0 . Otherwise, you will get empty body exception.
You can use StreamReader 's ReadToEndAsync() routine
Here is the code for the OnActionExecuting method:
public void OnActionExecuting(ActionExecutingContext context)
{
var request = context.HttpContext.Request;
string requestBody;
using (StreamReader reader = new StreamReader(request.Body))
{
requestBody= Task.Run(reader.ReadToEndAsync).Result;
}
//do something with the requestBody
}

ActionFilterAttribute on Web api call does not correctly redirect to the new location

My action filter attribute does not redirect to the new url i have defined:
public class RunOnServerAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
public ServerType Type;
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext filterContext)
{
switch (Type)
{
case ServerType.CMS:
if (!filterContext.Request.RequestUri.AbsoluteUri.StartsWith(Config.CMSUrl))
{
Uri correctedUri = new Uri($"{Config.CMSUrl.TrimEnd('/')}/{filterContext.Request.RequestUri.PathAndQuery.TrimStart('/')}");
var response = filterContext.Request.CreateResponse(System.Net.HttpStatusCode.Moved);
response.Headers.Location = correctedUri;
return;
// This does not seem to work
}
break;
}
base.OnActionExecuting(filterContext);
}
}
It just continues on with the normal request. I am debugging this by inspecting the Request.RequestUri in the executing api method
Sorry for not noticing it's a WebAPI project.
Composing the response should be a quick resolution.
var res = actionContext.Request.CreateResponse(HttpStatusCode.Redirect);
res.Headers.Location = new Uri("https://www.google.com");
actionContext.Response = res;
------------- Updated above. --------------
You should use the filterContext.Result and assign the ActionResult. Just like what you do in normal actions.
For instance,
var controller = (YourBaseControllerType)filterContext.Controller;
filterContext.Result = controller.RedirectToAction("actionName", "controllerName");
or
filterContext.Result = new RedirectResult(YourUrl);
OnActionExecuting is called before controller action method invoking, so after running filter method controller action replaces response. I think method OnActionExecuted is better place for your code.

WebClient UploadString Not Working

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;
}

Call Web API from MVC Controller using the same HttpClient

I have an MVC5 project, from the MVC controller I need to call the Web API method. The Web API uses token based authentication, so I have to pass the token for each call. I am using the code below to pass the token in the HTTP header:
HttpClient httpClient = new HttpClient();
string baseUrl = "http://localhost:60477/";
dynamic token = Session["token"];
if (token.AccessToken != null)
{
httpClient.DefaultRequestHeaders.Add("Authorization", String.Format("Bearer {0}", token.AccessToken));
}
There are multiple action methods in my controller, and I want to use a single HttpClient and headers, added in one place, instead of adding a header in each and every action method.
Where can I place the HttpClient headers registration code in the MVC application, so it can be common to all controllers? That means I don't want to repeat code, like adding the token in each and every action method. How can I do that?
Public ActionResult Postuser(UserModel user)
{
// post code
}
Public ActionResult getuser(UserModel user)
{
HttpResponseMessage response = httpClient.GetAsync(baseUrl + "api/Admin/GetStates").Result;
if (response.IsSuccessStatusCode)
{
string stateInfo = response.Content.ReadAsStringAsync().Result;
}
}
Public ActionResult PostRoles(RoleModel role)
{
// post roles code
}
You can try creating a small helper class for creating your httpclient object. Something like
public class HttpClientHelper
{
public static HttpClient GetHttpClient()
{
var MyHttpClient = new HttpClient();
dynamic _token = HttpContext.Current.Session["token"];
if (_token == null) throw new ArgumentNullException(nameof(_token));
MyHttpClient.DefaultRequestHeaders.Add("Authorization", String.Format("Bearer {0}", _token.AccessToken));
return MyHttpClient;
}
}
and then call it in your controllers as
public ActionResult getuser(UserModel user)
{
var httpClient = HttpClientHelper.GetHttpClient();
HttpResponseMessage response = httpClient.GetAsync(baseUrl + "api/Admin/GetStates").Result;
if (response.IsSuccessStatusCode)
{
string stateInfo = response.Content.ReadAsStringAsync().Result;
}
}
It is better to adhere to the Single Responsibility Principle and extract the interaction with another service in a it's own class, e.g.
public class ServiceClient : IServiceClient
{
private HttpClient m_Client;
public ServiceClient
{
m_Client = new HttpClient();
// Initialize the client as you need here
}
public void CallSomeMethod()
{
// Call method on the client
}
}
Then you inject the IServiceClient in your controller and just call it's methods. If you do not use injection (which I advise you do) you can just create a new instance in the controller's constructor.
You can try using an action filter in your controller. Try adding an override that looks something like this-
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
// some condition code to target a specific method in the controller
// Example
if (filterContext.ActionDescriptor.ActionName == "getuser") // <-- your method
{
// put your token based authentication code here
}
base.OnActionExecuting(filterContext);
}
The OnActionExecuting method is at the controller scope so you can have different logic for different controllers.
There's also an OnActionExecuted method override if you want to run code after your action method.
------edit--------------
As far as where to place your HttpClient code snippet, you can try this-
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpClient httpClient = new HttpClient();
string baseUrl = "http://localhost:60477/";
dynamic token = Session["token"];
if (token.AccessToken != null)
{
httpClient.DefaultRequestHeaders.Add(
"Authorization",
string.Format("Bearer {0}", token.AccessToken)
);
httpClient.BaseAddress = new Uri(baseUrl);
}
if(filterContext.ActionParameters.ContainsKey("httpClient"))
{
filterContext.ActionParameters["httpClient"] = httpClient;
}
else
{
// error
}
base.OnActionExecuting(filterContext);
}
So the HttpClient object along with the assignment of your baseUrl is established in OnActionExecuting. This code will run before any method returning a ActionResult in the controller you are refactoring. If you want to target some and not all methods, see the first example of OnActionExecuting above.
public ActionResult getuser(UserModel user, HttpClient httpClient)
{
HttpResponseMessage response = httpClient.GetAsync("api/Admin/GetStates").Result;
if(response.IsSuccessStatusCode)
{
string stateInfo = response.Content.ReadAsStringAsync().Result;
}
// the rest of your code for getuser..
return View();
}
Now your getuser method has an extra parameter ( HttpClient httpClient ).
why don't you move the code in Global asax or create custom Atribute?
here is one good link:
http://www.diaryofaninja.com/blog/2011/07/24/writing-your-own-custom-aspnet-mvc-authorize-attributes

No action was found on the controller 'Foo' that matches the request

I couldn't call web api with params from android. I can do without params so problem probably how I send params or how I get them.
Following code gives this error :
No action was found on the controller 'Foo' that matches the request.
Android
ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("token", session.getAccessToken()));
json = restClientService.getResponseAsJSON("http://192.168.2.242/WebApi/api/fbfeed/foo/", params);
--
private HttpResponse getWebServiceResponse(String URL,
ArrayList<NameValuePair> params) {
HttpResponse httpResponse = null;
try {
HttpParams httpParameters = new BasicHttpParams();
// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters);
HttpPost httpPost = new HttpPost(URL);
try {
httpPost.setEntity(new UrlEncodedFormEntity(params));
} catch (UnsupportedEncodingException e) {
}
httpResponse = httpClient.execute(httpPost);
Config
config.Routes.MapHttpRoute(name: "UserCreateApi", routeTemplate: "api/{controller}/{action}", defaults: new { action = "Foo" });
Controller
[AcceptVerbs("GET", "POST")]
public IHttpActionResult Foo([FromBody]string token)
{
//some code
}
Is your controller inheriting from ApiController? Can you hit the url from a browser on your local machine?

Categories

Resources