首页 > 解决方案 > 将对象(和子对象)从 Razor 页面发送到另一个页面

问题描述

我正在尝试将 ResumeInfo(Custom Object) 类型的对象从 razor 页面发送到另一个 razor 页面,它工作正常.....但我注意到该对象中的所有子对象都是空的,它们不应该是因为他们有价值观。
这是我从中创建对象的类,它有一个其他对象的列表(经验、语言、技能),当我将对象从一个 Razor 页面发送到另一个页面时,列表返回空,即使对象具有值,因为我在我将对象发送到另一个页面之前对其进行了测试。

  public class ResumeInfo
    {
        public string FullName { get; set; }
        public string Profession { get; set; }
        public List<string> Socials { get; set; }
        public List<Skill> Skills { get; set; }
        public List<Language> Languages { get; set; }
        public List<Experience> Experiences { get; set; }
        public string AboutMe { get; set; }

        public List<Language> GetLanguages()
        {
            if (Languages == null)
                Languages = new List<Language>();
            return Languages;
        }
        public List<Skill> GetSkills()
        {
            if (Skills == null)
                Skills = new List<Skill>();
            return Skills;
        }
        public List<Experience> GetExperiences()
        {
            if (Experiences == null)
                Experiences = new List<Experience>();
            return Experiences;
        }
    }

这就是我发送对象的方式:

public class ResumeFormModel : PageModel
    {
        [BindProperty]
        public ResumeInfo Info { get; set; }
        public IActionResult OnPost()
        {
            int counter = 0;
            var socials = Request.Form["Socials"];

            var languagesName = Request.Form["LanguagesName"];
            var languageValue = Request.Form["LanguagesValue"];

            var skillsName = Request.Form["SkillsName"];
            var skillsValue = Request.Form["SkillsValue"];

            var expTitle = Request.Form["ExperienceTitle"];
            var expText = Request.Form["ExperienceText"];

            foreach(string str in socials)
            {
                Info.Socials.Add(str);
                Console.WriteLine(str);
            }
            counter = 0;
            foreach(string str in languagesName)
                Info.GetLanguages().Add(new Language(str, Int32.Parse(languageValue[counter++])));
            counter = 0;
            foreach (string str in skillsName)
                Info.GetSkills().Add(new Skill(str, Int32.Parse(skillsValue[counter++])));
            counter = 0;
            foreach (string str in expTitle)
            {
                Info.GetExperiences().Add(new Experience(str, expText[counter++]));
                Console.WriteLine(str);
            }

            return RedirectToPage("GenerateResume", Info);

        }
    }

请注意,来自 Object(ResumeInfo) 的其他属性,例如 (FullName, Profession, AboutMe) 工作正常并且它们具有值,它只是列表和子对象。

这就是我接收对象的方式。

    public class GenerateResumeModel : PageModel
    {
        [BindProperty(SupportsGet = true)]
        public ResumeInfo Info { get; set; }
        public void OnGet()
        {
            //Console.WriteLine(Info.GetExperiences()[0].Name);
        }
    }

为什么不填充子对象?有没有其他方法可以发送对象?

标签: asp.net-corerazor-pages

解决方案


查看PageBase.RedirectToPage Method,我们可以看到 Object 是路由值。

在此处输入图像描述

在 Asp.net Core Razor 页面中,我们不能将复杂的对象作为路由数据传递。路线数据功能仅支持简单的对象,如intstring。如果要跨请求保留更复杂的对象,则需要使用Sessionsor TempData(由会话状态支持)。

因此,您可以参考以下步骤来启用会话并在跨请求之间传输复杂对象。

  1. 在 Startup.cs 中启用会话中间件:调用AddSessionin ConfigureServices,然后调用UseSessionin Configure

     public void ConfigureServices(IServiceCollection services)
     {
         services.AddDistributedMemoryCache();
    
         services.AddSession(options =>
         {
             options.IdleTimeout = TimeSpan.FromMinutes(10); //session expired time
             options.Cookie.HttpOnly = true;
             options.Cookie.IsEssential = true;
         });
    
         services.AddRazorPages();  
     }
    
     // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
     public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
     {
         ... 
         app.UseAuthentication();
         app.UseAuthorization();
         app.UseSession();
         app.UseEndpoints(endpoints =>
         {
             endpoints.MapRazorPages();
         });
     }
    
  2. 添加 Session 或 TempData 扩展来存储对象。

     //required
     //using Microsoft.AspNetCore.Http;
     //using Newtonsoft.Json;
     public static class SessionExtensions
     {
         public static void Set<T>(this ISession session, string key, T value)
         {
             session.SetString(key, JsonConvert.SerializeObject(value));
         }
    
         public static T Get<T>(this ISession session, string key)
         {
             var value = session.GetString(key);
             return value == null ? default : JsonConvert.DeserializeObject<T>(value);
         }
     }
    

    或者

     //Required
     //using Microsoft.AspNetCore.Mvc.ViewFeatures;
     //using Newtonsoft.Json;
     public static class TempDataExtensions
     {
         public static void Set<T>(this ITempDataDictionary tempData, string key, T value) where T : class
         {
             tempData[key] = JsonConvert.SerializeObject(value);
         }
    
         public static T Get<T>(this ITempDataDictionary tempData, string key) where T : class
         {
             object o;
             tempData.TryGetValue(key, out o);
             return o == null ? null : JsonConvert.DeserializeObject<T>((string)o);
         }
     }
    
  3. 使用 session 或 TempData 存储复杂对象:

    ResumeForm Post 方法:

         public IActionResult OnPost()
         {
             //set value for Info.
             ...
    
             //store value in session
             HttpContext.Session.Set<ResumeInfo>("Resume", Info);
             // use TempData store the object
             TempData.Set("Resume", Info);
    
             return RedirectToPage("GenerateResume", Info);
    
         }
    

    然后,GenerateResume 页面 Get 方法中的代码:

     public class GenerateResumeModel : PageModel
     {
         [BindProperty(SupportsGet = true)]
         public ResumeInfo Info { get; set; }
         public void OnGet()
         {
             var resume =  HttpContext.Session.Get<ResumeInfo>("Resume");
    
             var data = TempData.Get<ResumeInfo>("Resume");
             //Console.WriteLine(Info.GetExperiences()[0].Name);
         }
     }
    

测试结果是这样的:

在此处输入图像描述


推荐阅读