将对象(和子对象)从一个 Razor 页面发送到另一个

Sending objects(And Child Objects) from a Razor page to another

我正在尝试将 ResumeInfo(自定义对象)类型的对象从一个 razor 页面发送到另一个 razor 页面,它工作正常......但我注意到该对象中的所有子对象都是空的,它们不应该是因为他们有价值观。
这是我制作对象的 Class,它有一个其他对象列表(经验、语言、技能)当我将对象从一个 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);

        }
    }

请注意,对象 (ResumeInfo) 的其他属性(全名、专业、AboutMe)工作正常并且它们具有值,只是列表和子对象。

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

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

为什么不填充子对象?还有其他发送对象的方法吗?

查看PageBase.RedirectToPage Method,可以看到Object就是路由Values。

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

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

  1. 在Startup.cs中启用会话中间件:在ConfigureServices中调用AddSession,在Configure中调用UseSession

     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);
         }
     }
    

测试结果是这样的: