How pass objects from one page to another on ASP.Net Core with razor pages?

61,055

Solution 1

I don't know if that might help you or it is good practice for MVVM flavours like Razor, but inside ASP.NET Core API projects I often use custom global DI'ed services, like

public void ConfigureServices(IServiceCollection services)
{
    ...

    services.AddSingleton<IMyService, MyService>();

    ...

     services.AddMvc();
}

You can exchange data between your IndexModel and a CustomModel eg. by setting it like

public class CustomModel : PageModel
{
   public IMyService _myService;

   public CustomModel(IMyService myService)
   {
       _myService = myService;
   }

   public async Task<IActionResult> OnPostAsync(...)
   {
        ...

        _myService.SetDataOrSometing(...);

        ...

        return RedirectToPage();
   }
}

and retrieving it like

public class IndexModel : PageModel
{
    public IMyService _myService;

    public IndexModel(IMyService myService)
    {
        _myService = myService;
    }

    public void OnGet()
    {
        var data = _myService.GetDataOrSomething();
    }
}

From here you can also use an ObserveableCollection and register events to get the updates down to your PageModels.

IMHO this is a way to pass objects from one page to another with a clean separation of concerns.

Solution 2

You can pass parameters to specified handlers in the page model class, like this:

return RedirectToPage("Orders", "SingleOrder", new {orderId = order.Id});

Where the page model class method has this signature:

public void OnGetSingleOrder(int orderId)

If you are passing an object, you can pass the object directly, but in my experience any child objects are not populated.

Solution 3

The key here is that you need to pass an anonymous object whose property names match the routing constraints defined in the Razor Page.

For example, if you define an id (optional) routing constraint in the Razor Page:

@page "{id?}"

To redirect to that view passing a specific id, just do:

return RedirectToPage("PageName", new { id = 3 });

If you just one to redirect to the current page (but passing a specific id), just do:

return RedirectToPage(new { id = 3 });

If you just pass the number without the anonymous object it won't work.

Solution 4

Pass object from one page to another through Anchor Tag Helper.

  1. Model class.

    public class Car
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string Model { get; set; }
        public string Description { get; set; }
    }
    
  2. Cars - PageModel.

    public class CarsModel : PageModel
    {
        public List<Car> Cars { get; private set; } = new List<Car> {
            new Car{ ID = 1, Name = "Car1", Model = "M1", Description = "Some description" },
            new Car{ ID = 2, Name = "Car2", Model = "M2", Description = "Some description" },
            new Car{ ID = 3, Name = "Car3", Model = "M3", Description = "Some description" },
            new Car{ ID = 4, Name = "Car4", Model = "M4", Description = "Some description" }
        };
    }
    
  3. Cars - RazorPage(source of the pass-object) -> display all items(in our case cars) from the list of 'CarsModel'. In the 'Anchor Tag Helper' use 'asp-all-route-data' attribute, which is initialized with dictionary name as string(in our case 'dictCars').

    @page
    @using Newtonsoft.Json
    @model CarsModel
    
    @{
        ViewData["Title"] = "Cars";
    }
    
    <table>
        <thead>
            <tr>
                <th>
                    @Html.DisplayNameFor(model => model.Cars[0].Name)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Cars[0].Model)
                </th>
                <th></th>
            </tr>
        </thead>
        <tbody>
    
        @foreach (var car in Model.Cars)
        {
    
            Dictionary<string, string> dictCars = 
            new Dictionary<string, string> { { "passedObject", JsonConvert.SerializeObject(car) } };
    
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => car.Name)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => car.Model)
                </td>
                <td>
                    <a asp-page="./Details" asp-all-route-data="dictCars">Details</a>
                </td>
            </tr>
        }
        </tbody>
    </table>
    
  4. Details - PageModel(destination of the pass-object).

    public class DetailsModel : PageModel
    {
    
        public Car Car { get; set; }
    
        public IActionResult OnGet(string passedObject)
        {
    
            Car = JsonConvert.DeserializeObject<Car>(passedObject);
    
            if (Car == null)
            {
                return NotFound();
            }
    
            return Page();
        }
    }
    
  5. Details - RazorPage.

    @page
    
    @model DetailsModel
    
    @{
        ViewData["Title"] = "Car Details";
    }
    
    <h2>Details</h2>
    
    <div>
        <h4>Car</h4>
        <hr />
        <dl class="dl-horizontal">
            <dt>
                @Html.DisplayNameFor(model => model.Car.Name)
            </dt>
            <dd>
                @Html.DisplayFor(model => model.Car.Name)
            </dd>
            <dt>
                @Html.DisplayNameFor(model => model.Car.Model)
            </dt>
            <dd>
                @Html.DisplayFor(model => model.Car.Model)
            </dd>
            <dt>
                @Html.DisplayNameFor(model => model.Car.Description)
            </dt>
            <dd>
                @Html.DisplayFor(model => model.Car.Description)
            </dd>
        </dl>
    </div>
    

Solution 5

You can use the TempData decorator. It is available as a decorator or as a dictionary and its purpose is to keep an object between requests. In the background, the value is stored in a cookie or in the user session, at your choice. You can see more details about its use in the links below:

TempData at Microsoft Documentation
TempData in Learn Razor Pages (more practical)

Share:
61,055

Related videos on Youtube

gsaldana
Author by

gsaldana

Updated on October 22, 2021

Comments

  • gsaldana
    gsaldana over 2 years

    I'm developing a web application using Asp.net core 2.0 with razor pages. I'm creating an object with some data and want to send that object to another page.

    Actually I'm doing this:

    var customObject = new{
       //some values
    };
    return RedirectToPage("NewPage", customObject);
    

    I see that the url has the values of the object I'm sending, but I can't find how to take that values (in the NewPage instance).

    Can anybody knows how to share objects between razor pages? Is this the correct way to achieve it? or Is there another better way?

    Thanks in advance

    • Prashanth Benny
      Prashanth Benny over 6 years
      send the object on when you post it back from the view to the controller
    • Chris Pratt
      Chris Pratt over 6 years
      So it begins. The scourge of Web Forms, reborn as Razor Pages. When things are "magic", it's no longer obvious how to do simple things like this. Razor Pages or no, it works the same as any other HTTP request. You must post the values to the new URL, and then retrieve the data from the request body on the resulting URL.
    • Chris Pratt
      Chris Pratt over 6 years
      Forget what Microsoft says, save a kitten and don't use Razor Pages.
    • McGuireV10
      McGuireV10 over 6 years
      Parameters in a query string isn't exactly "magic" -- and that's all handlers and parameter-passing are for data-sharing via GET in Razor Pages.
    • Ryan
      Ryan over 5 years
      I am trying pretty hard to avoid Razor Pages, but even in my MVC Core 2.2 app the Identity scaffolding forced me to use Razor all over. Any way to avoid that? (easily?)
    • John81
      John81 almost 5 years
      No way to avoid Razor Pages. I tried rewriting the Identity scaffolding in MVC and gave up. I begrudgingly have accepted that Razor Pages are here to stay and where MS wants us to head so might as well get over and and accept them.
  • Mert Gülsoy
    Mert Gülsoy about 5 years
    How do you know which client put which data to there? If and only if one client is using the system, then there is no problem. You can use IMemoryCache with a lifetime. The approach defined in this answer is not a good practice.
  • Bennybear
    Bennybear over 4 years
    I agree. This is the correct answer. I've tested it with multiple key value pairs, and it works like a charm each time. You may also want to consider using session state.
  • Herman Van Der Blom
    Herman Van Der Blom over 4 years
    this is the page that describes it: docs.microsoft.com/en-us/dotnet/api/…
  • FoggyDay
    FoggyDay about 4 years
    Agreed: hillstuk gave the "correct answer" for passing data between ASP.Net Core MVC Razor views Specifically: 1) Define a view model. It can be a POCO. Put it in your "Models" folder. 2) Declare the view model in your view's parameter list. 3) Create an anonymous instance in your RedirectToPage() call.
  • 1atera1usz
    1atera1usz about 4 years
    Just to add, when you are redirecting to the same page: if any of the parameters to the page handler come from the route, you can omit them. For example if the OnGet looks like: public async Task<IActionResult> OnGet([FromRoute]string userId, [FromQuery]bool? cs = null) When redirecting from the same page just do: return RedirectToPage(new { cs = true });
  • BloodyMettle
    BloodyMettle over 3 years
    Though it's old, the accepted answer is also not working in a distributed system with multiple nodes, if the singleton service is not using some other mechanism to store the data for every node. It also needs to delivers a unique key for retrieval for exactly that users+requests data.