How to retrieve current application root URL in .net core within a static method? - asp.net-core

I am currently using the Request.Scheme and Request.Host to composite Uri object to get AbsoluteUri for my .net core MVC application.
Uri location = new Uri($"{Request.Scheme}://{Request.Host}");
string applicationRootURL = location.AbsoluteUri;
But this only works in a non-static method.
As I need to re-use this method in another controller, I am thinking to make this action method static. If I do that, the compiler will complaint about the Request.Scheme and Request.Host.
I am wondering what's other options I have to achieve this?
Thank you.
UPDATE:
This is what I have for ControllerA with ActionMethodA
public class ControllerA
{
public bool ActionMethodA()
{
Uri location = new Uri($"{Request.Scheme}://{Request.Host}");
string applicationRootURL = location.AbsoluteUri;
return false;
}
}
And in another ControllerB, I want to ActionMethodB to invoke ActionMethodA from ControllerA:
public class ControllerB
{
public void ActionMethodB()
{
var result = ActionMethodA();
}
}
Is creating an Extension Method to the ControllerA is the most proper way to handle this kind of scenario?
Thank you.

You can also define an extension method directly for the HttpRequest class and use the BuildAbsolute method of the UriHelper class to build the uri.
public static class HttpRequestExtensions
{
public static string GetURI(this HttpRequest request)
{
return UriHelper.BuildAbsolute(request.Scheme, request.Host);
}
}
And use it:
public IActionResult ContollerMethod()
{
var uri = Request.GetURI();
// your code
}

You can write an extension method to a controller or HttpContext object. In the following example I have added an extension method to the controller.
public static class ControllerExtensions
{
public static string GetURI(this Controller controller)
{
Uri location = new Uri($"{ controller.Request.Scheme}://{controller.Request.Host}");
string applicationRootURL = location.AbsoluteUri;
return applicationRootURL;
}
}
Once the extension method is written you can call it in the following manner.
public IActionResult Index()
{
var url = this.GetURI();
return View();
}
Make sure to import namespace of an extension method in your calling code

Related

common code for all methods in a controller class

I have 10 controllers that use the same block of code but I can't figure out how to write the code once and use it everywhere.
I have to define an object called:
requiredStructuralSupportParameters
, then set 3 fields in the object.
This is one of the controller methods that uses it:
public class StructureController : Controller
{
public IActionResult Index()
{
var requiredStructuralSupportParameters = new Structure.RequiredInfo()
{
Steel = "1500y",
Concrete = "5500l",
Rebar = "95000y"
};
var response = callToAPI(requiredStructuralSupportParameters);
return response.Results;
}
}
I have tried taking that code out and putting it at the top of the controller class and making it public, but then my controllers can't see it and I get nullreferenceexception errors.
So it only works when I put it directly in the controller methods.
Is there a way to make this so that all controllers can re-use the same block of code?
public class StructureController : Controller
{
protected YourType _requiredStructuralSupportParameters;
public StructureController()
{
this._requiredStructuralSupportParameters = new Structure.RequiredInfo()
{
Steel = "1500y",
Concrete = "5500l",
Rebar = "95000y"
};
}
}
then have your other controllers inherit your StructureController:
public SomeController : StructureController{
public IActionResult Index() {
var response = callToAPI(this._requiredStructuralSupportParameters);
return response.Results;
}
}
haven't tested it but i hope you get an idea

How to inject HttpHeader value in controller?

I have Web API developed using ASP.NET Core API. Every incoming request has a custom header value inserted. eg x-correlationid. The controller use this value for logging and tracing the request.
Currently I'm reading the value in each controller as below
[Route("api/[controller]")]
public class DocumentController : Controller
{
private ILogger<TransformController> _logger;
private string _correlationid = null;
public DocumentController(ILogger<DocumentController > logger)
{
_logger = logger;
_correlationid = HttpContext.Request.Headers["x-correlationid"];
}
[HttpPost]
public async Task<intTransform([FromBody]RequestWrapper request)
{
_logger.LogInformation("Start task. CorrelationId:{0}", _correlationid);
// do something here
_logger.LogInformation("End task. CorrelationId:{0}", _correlationid);
return result;
}
}
I think this is against DI rules.
Instead of reading the value inside the controller's constructor, I want to inject the value in the controller's constructor.
Or
Can middleware read the x-correlationid and *somehow* make it available to all the controllers so we don't have to inject it in any controller?
What would be a better option here?
Instead of reading the value inside the controller's constructor, I want to inject the value in the controller's constructor.
You can't inject the value itself into the constructor of the api controller, because at the time of construction the HttpContext is going to be null.
One "injection-style" option would be to use the FromHeaderAttribute in your actions:
[HttpPost]
public async Task<int> Transform(
[FromBody]RequestWrapper request,
[FromHeader(Name="x-correlationid")] string correlationId)
{
return result;
}
Can middleware read the x-correlationid and somehow make it available to all the controllers so we don't have to inject it in any controller?
I think a middleware solution would probably be overkill for what you need. Instead, you can create a custom base class that derives from Controller and have all your Api controllers derive from that.
public class MyControllerBase : Controller
{
protected string CorrelationId =>
HttpContext?.Request.Headers["x-correlationid"] ?? string.Empty;
}
[Route("api/[controller]")]
public class DocumentController : MyControllerBase
{
private ILogger<TransformController> _logger;
public DocumentController(ILogger<DocumentController> logger)
{
_logger = logger;
}
[HttpPost]
public async Task<intTransform([FromBody]RequestWrapper request)
{
_logger.LogInformation($"Start task. CorrelationId:{CorrelationId}");
// do something here
_logger.LogInformation($"End task. CorrelationId:{CorrelationId}");
return result;
}
}
This is what I came up with. I think i can also unit test it.
public interface IRequestContext
{
string CorrelationId { get; }
}
public sealed class RequestContextAdapter : IRequestContext
{
private readonly IHttpContextAccessor _accessor;
public RequestContextAdapter(IHttpContextAccessor accessor)
{
this._accessor = accessor;
}
public string CorrelationId
{
get
{
return this._accessor.HttpContext.Request.Headers[Constants.CORRELATIONID_KEY];
}
}
}
then in startup's configureservice method register the adapter
services.AddSingleton<IRequestContext, RequestContextAdapter>();
and inject it in controller
[Route("api/[controller]")]
public class DocumentController : Controller
{
private ILogger<TransformController> _logger;
private IRequestContext _requestContext = null;
public DocumentController(ILogger<DocumentController > logger,IRequestContext requestContext)
{
_logger = logger;
_requestContext = requestContext;
}
[HttpPost]
public async Task<intTransform([FromBody]RequestWrapper request)
{
_logger.LogInformation("Start task. CorrelationId:{0}", _requestContext.CorrelationId);
// do something here
_logger.LogInformation("End task. CorrelationId:{0}", _requestContext.CorrelationId);
return result;
}
}
Depending on your needs one of following is suitable:
If you need your header values at action level, then using FromHeaderAttribute sounds better (lighter and easier).
If you need to use this header value in lower layers like Repository or DAL, which will be instantiated before Controller has been initialized, then consider to use middleware to get header values initialized and available for other components.

InstantiationException while using action composition in Play framwework 2.1

I'm trying to use my first Action within a controller method with Play (2.1.x) but I get an InstantiationException error that don't really helps me understanding the problem.
Here is my method declaration inside my main controller :
public class Api extends Controller {
public class CORSAction extends Action.Simple {
public Result call(Http.Context ctx) throws Throwable {
Logger.info("Calling CORSAction for " + ctx);
Result result = this.delegate.call(ctx);
Http.Response response = ctx.response();
response.setHeader("Access-Control-Allow-Origin", "*");
return result;
}
}
#With(CORSAction.class)
#Transactional
public static Result login() {
// .... some code
return ok(Json.toJson(response));
}
}
Where did I made a mistake ?
I use IntelliJ Ultimate Edition for coding.
Thanks
Found by myself, the Action Class MUST be declared in a separated file otherwise it generates an InstantiationException.

how to handle ActionResult in custome class?

i have a class (in project by mvc4 razor on .net 4.5) and want to handle a Redirecting method on it and do not want inherit from controller class.
how can i handle this?it returns ActionResult to redirecting user in some cases like log outing
my main class:
public class SecuritySrv
{
public ActionResult Redirect()
{
return RedirectToAction("Logout", "Account", new { area = "" });
}
}
and i want to use it in some controllers like below:
public ActionResult AccountHome()
{
SecuritySrv SecurityService =new SecuritySrv()
if(.....)
return SecurityService.Redirect();
return view();
}
You can use this code anywhere, and you don't need an UrlHelper or access to the context, so you don't need to inherit the Controller class.
RouteValueDictionary rvd = new RouteValueDictionary
{
{"controller", "Profile"},
{"action", "Users"},
{"area", ""}
};
return new RedirectToRouteResult(rvd);
The RedirectToAction method of controller is just a helper for creating RedirectToRouteResult, you can create it by yourself in your class:
public class SecuritySrv
{
public ActionResult Redirect()
{
RouteValueDictionary routeValues = new RouteValueDictionary();
routeValues["action"] = "Logout";
routeValues["controller"] = "Account";
routeValues["area"] = "";
return new RedirectToRouteResult(routeValues);
}
}
And call this method from your controller in the way you wanted to.

How do you mock the querystring in a WCF service?

I have a WCF service which has methods that depend on reading values (OData) from the http request's querystring. I'm trying to write unit tests which inject in mock values into the querystring, then when I call the method it would use these mock values rather than erroring due to the request context not being available.
I've tried using WCFMock (which is based on Moq) however I don't see a way to set or get the querystring from the WebOperationContext that it provides.
Any ideas?
I ended up using the IOC pattern to solve this, creating an IQueryStringHelper interface that is passed into the constructor of the service. If it isn't passed in then it'll default to use the "real" QueryStringHelper class. When running test cases, it'll use an overloaded service constructor to pass in the TestQueryStringHelper instance, which lets you set a mock value for the querystring.
Here is the querystring helper code.
public interface IQueryStringHelper {
string[] GetParameters();
}
public class QueryStringHelper : IQueryStringHelper {
public string[] GetParameters() {
var properties = OperationContext.Current.IncomingMessageProperties;
var property = properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
string queryString = property.QueryString;
return queryString.Split('&');
}
}
public class TestQueryStringHelper : IQueryStringHelper {
private string mockValue;
public TestQueryStringHelper(string value) {
mockValue = value;
}
public string[] GetParameters() {
return mockValue.Split('&');
}
}
And the service implementation:
public partial class RestService : IRestService {
private IAuthenticator _auth;
private IQueryStringHelper _queryStringHelper;
public RestService() : this(new Authenticator(), new QueryStringHelper()) {
}
public RestService(IAuthenticator auth, IQueryStringHelper queryStringHelper = null) {
_auth = auth;
if (queryStringHelper != null) {
_queryStringHelper = queryStringHelper;
}
}
}
And how to consume it from a test case:
string odata = String.Format("$filter=Id eq guid'{0}'", "myguid");
var service = new RestService(m_auth,new TestQueryStringHelper(odata));
var entities = service.ReadAllEntities();
Hopefully this helps someone else.