0

I have a controller that is made with ASP.NET and I really want to simplify that thing with quick view:

// REST representation of Storage
// There is always at least two options to view them
// Data as is or Quick view at metrics averages
[Route("metrics")]
public class MetricsController : Controller
{
    // Get raw Storage object
    [HttpGet]
    public IActionResult GetStorageView()
    {   
        // TODO: do not use in production
        WSManModule.HyperVMetric.test(false);
        //

        var response = MetricsService.Instance.GetRawMetrics();

        if (response == null)
        {
            return NotFound();
        }

        if (Request.QueryString.Value == "?q=quick")
        {
            return Ok(new StorageQuickView(response));
        }

        return Ok(response);
    }

    // Get metrics for specific device
    [HttpGet("{deviceName}")]
    public IActionResult GetDeviceView(string deviceName)
    {
        var response = MetricsService.Instance.GetDeviceMetrics(deviceName);

        if (response == null)
        {
            return NotFound();
        }

        if (Request.QueryString.Value == "?q=quick")
        {
            return Ok(new DeviceQuickView(response));
        }

        return Ok(response);
    }

    // Get metrics for specific component within the device
    [HttpGet("{deviceName}/{componentName}")]
    public IActionResult GetComponentView(string deviceName, string componentName)
    {
        var response = MetricsService.Instance.GetComponentMetrics(deviceName, componentName);

        if (response == null)
        {
            return NotFound();
        }

        if (Request.QueryString.Value == "?q=quick")
        {
            return Ok(new ComponentQuickView(response));
        }

        return Ok(response);
    }
}

now it does have a lot of repetition and I don't like it. Is there any way to do it right with optional parameters like {quick?} or something similar?

Simply: I want to perform different operations if we have /quick at the end of the route or no.

NightOwl888
  • 55,572
  • 24
  • 139
  • 212
Roman
  • 733
  • 1
  • 5
  • 14
  • 1
    If this is asp core you can do some logic after your response has been processed by controller using middleware. https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?tabs=aspnetcore2x – vasil oreshenski Feb 22 '18 at 17:18

2 Answers2

1

Just accept the q parameter with your actions:

// Get raw Storage object
[HttpGet]
public IActionResult GetStorageView(string q)
{   
    // TODO: do not use in production
    WSManModule.HyperVMetric.test(false);
    //

    var response = MetricsService.Instance.GetRawMetrics();

    if (response == null)
    {
        return NotFound();
    }

    if (q == "quick")
    {
        return Ok(new StorageQuickView(response));
    }

    return Ok(response);
}

// Get metrics for specific device
[HttpGet("{deviceName}")]
public IActionResult GetDeviceView(string deviceName, string q)
{
    var response = MetricsService.Instance.GetDeviceMetrics(deviceName);

    if (response == null)
    {
        return NotFound();
    }

    if (q == "quick")
    {
        return Ok(new DeviceQuickView(response));
    }

    return Ok(response);
}

The action method parameters are not just derived from routes. The values come from Value Providers, and one of the default providers parses the query string. So, you only need to add the query string value to your action method parameters rather than parsing or comparing the query string manually.

NightOwl888
  • 55,572
  • 24
  • 139
  • 212
  • I've also found [FromQuery] thing in the web, how's that different from yours? – Roman Feb 23 '18 at 12:36
  • `[FromQuery]` and other similar attributes allow you to specify *which* value provider to try to get the value from, overriding the default behavior of trying them in registered order. However, AFAIK that attribute isn't available in MVC 5, only in Web API and ASP.NET Core. – NightOwl888 Feb 23 '18 at 14:42
0

you can create a private method like this:

private IAction ProcessResponse<T>(IMyResponseType response)
{
    if(response == null)
    {
        return NotFound();
    }

    if (Request.QueryString.Value == "?q=quick")
    {
        var okInstance = (T) Activator.CreateInstance(typeof (T), response);
        return Ok(okInstance);
    }

    return Ok(response);
}

and use it like this:

// Get metrics for specific component within the device
[HttpGet("{deviceName}/{componentName}")]
public IActionResult GetComponentView(string deviceName, string componentName)
{
    var response = MetricsService.Instance.GetComponentMetrics(deviceName, componentName);

    return ProcessResponse<ComponentQuickView>(response);
}

// Get raw Storage object
[HttpGet]
public IActionResult GetStorageView()
{   
    // TODO: do not use in production
    WSManModule.HyperVMetric.test(false);
    //

    var response = MetricsService.Instance.GetRawMetrics();

    return ProcessResponse<StorageQuickView>(response);
}
DotNet Fan
  • 383
  • 2
  • 4
  • 15