5
\$\begingroup\$

I have an action that takes an id as a parameter and gets the corresponding item with the help of a web service. The web service's method that returns the item will either return the item with the requested id, or will create a new item (new version of the item) with a new id. So, in the case that a new item is created, the response's header should be updated with the new item's id.

Here's what the route corresponding to that controller action looks like:

public override void RegisterArea(AreaRegistrationContext context)
{
    context.MapRoute(
        "default",
        "MyArea/{Controller}/{action}/{id}",
        new { controller = "MyController", action = "Index", id = UrlParameter.Optional }
    );
}

So when an user requests the item with the id 12, the request's path will look like:

MyArea/MyController/MyAction/12

Let's say the web service creates a new version of the above item, and its id is 13, I'd like to update the URL accordingly. Here's what my action looks like:

[HttpGet]
public async Task<ActionResult> EditItem(int id)
{
    try
    {
        Item myItem = await _myWS.Channel.GetItemAsync(id);

        // If a new version has been created, change the url in order to show the new id
        if (myItem.Id != id)
        {
            Response.StatusCode = 301;
            string newUrl = Request.Path;
            int lastSlashIndex = newUrl.LastIndexOf("/");
            if (lastSlashIndex > 0)
                newUrl = newUrl.Substring(0, lastSlashIndex + 1) + myItem.Id;

            Response.AddHeader("Location", newUrl);
            Response.End();
        }

        return View("MyView", (ItemViewModel)myItem);
    }
    catch (Exception ex)
    {
        throw new ApplicationException(ex.Message);
    }
}

I was wondering if there was a better way to reconstruct the URL with the updated id. I also tried reconstructing the URL with the Request.RequestContext.RouteData.Values, but I thought the code was less readable and more complicated, but I don't like the string replace neither, because I think it's less long term friendly.

Bonus

The reason I reconstructed the URL this way instead of a simple redirection it's because I thought the way I was doing avoided a second call to the action, but I was wrong. Is there a "hack" to avoid redirection and to just update the shown URL?

\$\endgroup\$
4
\$\begingroup\$

I believe you want RedirectToActionPermanent:

if (myItem.Id != id)
{
    return RedirectToActionPermanent("EditItem", new { id = id })
}
\$\endgroup\$
  • \$\begingroup\$ Thank you for your answer. You are very correct about that. It would indeed be more readable, but I'd like to avoid my action to get called again, because that means the web service method GetItemAsync would get called twice needlessly. See, when a new item is created, that method returns the new item, so redirecting to the same action would call again the method to get the same item, so I'm trying to avoid that. I'll edit my post accordingly, because it lacks this slight precision. \$\endgroup\$ – actaram Mar 20 '17 at 15:41
  • \$\begingroup\$ Are you sure your current method doesn't do a redirect and reload the page? Check the browser's network tools and Fiddler. \$\endgroup\$ – Jason P Mar 20 '17 at 15:45
  • \$\begingroup\$ I'll be damned, I was sure it was a hack to avoid redirection, but it does redirect anyways. Is there a way to only change the URL without redirecting? \$\endgroup\$ – actaram Mar 20 '17 at 15:49
  • \$\begingroup\$ The only way I know of is the javascript history api, specifically the pushState function. \$\endgroup\$ – Jason P Mar 20 '17 at 15:54
  • \$\begingroup\$ Thanks Jason for your time. I'll wait a little bit to see if others would know of a better way to achieve what I'm trying to and other else I'll accept your answer. \$\endgroup\$ – actaram Mar 20 '17 at 16:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.