Kamel Yehya
Kamel Yehya

Reputation: 33

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

I am trying to send an Object of type ResumeInfo(Custom Object) from a razor page to another razor page and it's working fine.....but I noticed that all child objects within that object are null, they are not supposed to be because they have values.
This is the Class that I made the object from, it has a List of other objects (Experience, Language, Skill) the lists are returning empty when I send the object from one Razor page to another, even though the Objects have values because I tested them before I sent the object to the another Page.

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

This is how I am sending the object:

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

        }
    }

Please note that other properties from the Object(ResumeInfo) like (FullName, Profession, AboutMe) are working fine and they have values, it's jus the Lists and the Child Objects.

And this is how I am receiving the object.

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

Why aren't the Child Objects being populated? is there any other way to send the object?

Upvotes: 0

Views: 649

Answers (1)

Zhi Lv
Zhi Lv

Reputation: 21408

Check the PageBase.RedirectToPage Method, we can see that the Object is the route Values.

enter image description here

In the Asp.net Core Razor Page, we can't pass the complex objects as route data. The route data feature only supports simple objects like int and string. If you want to retain more complex objects across requests, you need to use Sessions or TempData(backed by session state).

So, you could refer the following steps to enable session and transfer complex objects between across requests.

  1. Enable the session middleware in the Startup.cs: call AddSession in ConfigureServices, and call the UseSession in 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. Add Session or TempData extension to store objects.

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

    Or

     //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. Use session or TempData to store the complex objects:

    ResumeForm Post method:

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

    Then, code in the GenerateResume page Get method:

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

The test result like this:

enter image description here

Upvotes: 2

Related Questions