如何在ASP.Net Core Razor页面中从一个页面传递对象到另一个页面?

33

我正在使用Asp.net core 2.0和razor页面开发Web应用程序。我创建了一个带有一些数据的对象,并希望将该对象发送到另一个页面。

实际上,我正在执行以下操作:

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

我发现URL中有我发送的对象的值,但是我找不到如何在NewPage实例中获取这些值。

有人知道如何在Razor页面之间共享对象吗?这是正确的实现方式吗?还是有更好的方法?

提前致谢。


当您从视图发送对象回控制器时,请将其打开。 - Prashanth Benny
开始了。Web Forms的灾难,以Razor Pages的形式重生。当事情变得“神奇”时,像这样做简单的事情就不再明显了。无论是Razor Pages还是其他任何HTTP请求,它的工作方式都是相同的。您必须将值发布到新URL,然后从生成的URL的请求正文中检索数据。 - Chris Pratt
不要听微软的话,拯救小猫咪,不要使用Razor Pages。 - Chris Pratt
查询字符串中的参数并不是“神奇”的——这就是所有处理程序和参数传递的目的,通过Razor Pages上的GET实现数据共享。 - McGuireV10
我很努力地避免使用Razor Pages,但即使在我的MVC Core 2.2应用程序中,Identity脚手架也迫使我在各个方面都使用Razor。有什么方法可以轻松地避免这种情况吗? - Ryan
2
无法避免Razor Pages。我尝试在MVC中重写Identity脚手架,但最终放弃了。我不情愿地接受了Razor Pages已经到来并且是微软希望我们前进的方向,所以最好放下成见并接受它们。 - John81
6个回答

61
您可以向页面模型类中的指定处理程序传递参数,方法如下:

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

页面模型类方法的签名如下:

public void OnGetSingleOrder(int orderId)

如果您要传递一个对象,您可以直接传递该对象,但是根据我的经验,任何子对象都不会被填充。


2
我同意。这是正确的答案。我已经使用多个键值对进行了测试,每次都能完美运行。您可能还想考虑使用会话状态 - Bennybear
2
这是描述它的页面:https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.razorpages.pagebase.redirecttopage?view=aspnetcore-2.2#Microsoft_AspNetCore_Mvc_RazorPages_PageBase_RedirectToPage_System_String_System_String_System_Object_System_String_ - Herman Van Der Blom

14
关键在于你需要传递一个匿名对象,其属性名称与在Razor Page中定义的路由约束相匹配。
例如,如果您在Razor Page中定义了一个'id'(可选)路由约束:
@page "{id?}"
要重定向到该视图并传递特定的'id',只需执行:
return RedirectToPage("PageName", new { id = 3 });

如果您只想重定向到当前页面(但传递特定的id),只需执行以下操作:

return RedirectToPage(new { id = 3 });
如果您只传递数字而没有匿名对象,则无法正常工作。

补充一下,当您在重定向到同一页时: 如果页面处理程序的任何参数来自路由,则可以省略它们。 例如,如果OnGet看起来像: public async Task<IActionResult> OnGet([FromRoute]string userId, [FromQuery]bool? cs = null)当从同一页重定向时,只需执行以下操作: return RedirectToPage(new { cs = true }); - 1atera1usz

8
通过锚点标签助手将对象从一个页面传递到另一个页面。
  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>
    

6
您可以使用TempData装饰器,它可用作装饰器或字典,其目的是在请求之间保留对象。在后台,该值存储在cookie或用户会话中,由您选择。您可以在以下链接中了解有关其使用的更多详细信息:

Microsoft文档中的TempData
Learn Razor Pages中的TempData(更具实践性)

0

我不知道这是否对你有所帮助,或者在类似Razor的MVVM风格中是否是最佳实践,但在ASP.NET Core API项目中,我经常使用自定义全局DI服务,例如

public void ConfigureServices(IServiceCollection services)
{
    ...

    services.AddSingleton<IMyService, MyService>();

    ...

     services.AddMvc();
}

您可以通过设置IndexModelCustomModel之间的数据来进行交换,例如:

public class CustomModel : PageModel
{
   public IMyService _myService;

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

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

        _myService.SetDataOrSometing(...);

        ...

        return RedirectToPage();
   }
}

并像这样检索它

public class IndexModel : PageModel
{
    public IMyService _myService;

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

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

从这里开始,您还可以使用ObservableCollection并注册事件,以便将更新传递到您的PageModels。

在我看来,这是一种通过清晰地分离关注点来在页面之间传递对象的方式。


16
您如何知道哪个客户端将数据放到那里?只有一个客户端使用系统时,就没有问题。您可以使用具有生命周期的IMemoryCache。本答案中定义的方法不是一个好的实践。 - Mert Gülsoy
2
同意:hillstuk在传递ASP.Net Core MVC Razor视图之间的数据方面给出了"正确答案"。具体来说:1)定义一个视图模型。它可以是POCO。将其放在“Models”文件夹中。2)在视图的参数列表中声明视图模型。3)在RedirectToPage()调用中创建一个匿名实例。 - FoggyDay
尽管这个答案已经有些老了,但是在一个具有多个节点的分布式系统中,如果单例服务没有使用其他机制来为每个节点存储数据,则该答案也不起作用。 它还需要提供一个唯一的检索键,以精确获取那些用户和请求数据。 - BloodyMettle
我们能否使用这种方法来处理Transient而不是Singleton? - AHMAD EZZAT
一个客户端解决方案应用于多线程服务器应用程序。会出现什么问题? - Elger Mensonides

0
使用“重定向”方法:
return Redirect("/Home/NewPage?id=" + customObject.Id);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接