How can I send the model from MVC Controller Action to Razor Page (Asp.Net MVC Core 6.)?

mehmood tekfirst 766 Reputation points
2022-08-12T15:04:01.743+00:00

Hi,

How can I send the model from MVC Controller Action to Razor Page ? I am developing in Asp.Net MVC Core 6.

I added the view

This is the controller action

public async Task<IActionResult> ParamIndex(string path = "/locations/eng/", string apiKey = "")  
        {  
            ViewBag.SrvDtTime = DateTime.Now.ToString("MM/dd/yyyy HH:mm");  
            int franchiseId = 0;  
            int.TryParse(apiKey, out franchiseId);  
            FranchiseWidgetSetting? windgetSetting = null;  
            if (!string.IsNullOrWhiteSpace(path) || !string.IsNullOrWhiteSpace(apiKey))  
            {  
                windgetSetting = await _widgetSettingsRepository.FindFranchiseWidgetSettings(franchiseId, 0, apiKey, string.Empty, path);  
            }             
            return View("~/Views/Param/ParamIndex.cshtml", windgetSetting );  
        }  

this is the page view

@page "{path:string,apiKey:string}"  
@model RentalWidget.Views.Home.ParamWidget.ParamPageModel  
@using   RentalWidget.Models.DBEntities.Franchises  
@model FranchiseWidgetSetting  
@{  
  }  
  
<div id="SearchVehiclePage">  
    @await Html.PartialAsync("ParamSearchCar.cshtml",Model)  
</div>  

The Exception is related to Null Exception and It always return null.

This is the page model but it doesn't receive any debugger. I placed some debugger point in it but the debugger doesn't hit here.

public class ParamPageModel : PageModel  
    {  
        [BindProperty(SupportsGet = true)]  
        public string Path { get; set; } = "";  
  
        [BindProperty(SupportsGet = true)]  
        public string ApiKey { get; set; } = "";  
        public void OnGet()  
        {  
        }  
    }  

Either correct me or bring a good/recommended solution.
Thank you

ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,140 questions
0 comments No comments
{count} votes

Accepted answer
  1. Zhi Lv - MSFT 32,006 Reputation points Microsoft Vendor
    2022-08-16T03:12:52.97+00:00

    Hi @mehmood tekfirst ,

    You can try to convert the Razor pages to a MVC views, then in the controller, return the MVC view with the model.

    Code like this:

    Create a ParamModel: 231333-parammodel.txt

    231237-image.png

    Controller: 231361-controller.txt

    231275-231239-image.png

    Right click the Param folder and add a MVC view (ParamIndex.cshtml):

    231286-231236-image.png

    Then the ParamIndex.cshtml like this: 231352-paramindex.txt

    231334-231284-image.png

    If you still want to use Razor Page, you can add the Razor Pages in the Pages folder, then in the controller, use the Redirect method to redirect to the Razor pages.

    Code like this:

    Controller:

    return Redirect("/razorindex?path="+item.Path+"&apikey="+item.ApiKey);  
    

    and in the razor page, the @page like this: 231362-paramrazorindex.txt

    231363-231238-image.png

    Then, in the Razor Page's Get method, receive the parameter, like this:

    231287-231170-image.png

    [Note] in this method, you need to register the Razor Page service and middleware.

    231288-231322-image.png

    The output like this: when access the Home controller Index action, it will redirect to the ParamRazorIndex Razor page.

    231364-231321-image.png


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,
    Dillion

    2 people found this answer helpful.

6 additional answers

Sort by: Most helpful
  1. Bruce (SqlWork.com) 55,041 Reputation points
    2022-08-12T16:00:22.68+00:00

    Mvc controllers do not support calling razor pages instead of views. Your sample code is just using the razor page model as a view model, none of the methods will be called. The called razor view will just have a reference to this model and can use the properties like any view model.

    1 person found this answer helpful.

  2. AgaveJoe 26,186 Reputation points
    2022-08-19T12:13:29.26+00:00

    There are several fundamental issues with your GitHib project. The sample project is missing the Razor Pages middleware. The Razor Page is within the View/Home folder which is the wrong location. By default Razor Pages are located in the Pages folder and the reason for the 404. The Razor page renders a partial but the partial is in the Home/View folder which is the wrong location too.

    Lastly, your project does not properly maintain state as explained in this and your other threads on this subject.

    1 person found this answer helpful.

  3. AgaveJoe 26,186 Reputation points
    2022-08-19T15:46:41.61+00:00

    I think either controller or razor pages should be used but not both at once.

    It's odd to purposely use two different server side UI frameworks in the same project but it is possible to combine MVC and Razor Pages in a single web application. From my testing, the service order does not matter. What matters are the folders. Using a default configuration, Razor Page needs a Pages folder and MVC needs a Views folder as explained in my last post.

    var builder = WebApplication.CreateBuilder(args);  
      
    // Add services to the container.  
    builder.Services.AddRazorPages();  
    builder.Services.AddControllersWithViews();  
      
    var app = builder.Build();  
      
    // Configure the HTTP request pipeline.  
    if (!app.Environment.IsDevelopment())  
    {  
        app.UseExceptionHandler("/Home/Error");  
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.  
        app.UseHsts();  
    }  
      
    app.UseHttpsRedirection();  
    app.UseStaticFiles();  
      
    app.UseRouting();  
      
    app.UseAuthorization();  
    app.MapRazorPages();  
    app.MapControllerRoute(  
        name: "default",  
        pattern: "{controller=Home}/{action=ParamIndex}/{id?}");  
      
    app.Run();  
      
    

    The only thing left is to make sure you have Pages and View folders.

    232870-capture.png

    1 person found this answer helpful.
    0 comments No comments

  4. AgaveJoe 26,186 Reputation points
    2022-08-19T19:46:19.7+00:00

    I made a few changes to you source code but I do not have push rights so I cannot add a new branch.

    The highlights are adding Session.

    var builder = WebApplication.CreateBuilder(args);  
      
    // Add services to the container.  
      
    builder.Services.AddRazorPages();  
    builder.Services.AddControllersWithViews();  
      
    builder.Services.AddDistributedMemoryCache();  
      
    builder.Services.AddSession(options =>  
    {  
        options.IdleTimeout = TimeSpan.FromSeconds(10);  
        options.Cookie.HttpOnly = true;  
        options.Cookie.IsEssential = true;  
    });  
      
    builder.Services.AddDistributedMemoryCache();  
      
    builder.Services.AddSession(options =>  
    {  
        options.IdleTimeout = TimeSpan.FromSeconds(10);  
        options.Cookie.HttpOnly = true;  
        options.Cookie.IsEssential = true;  
    });  
      
    var app = builder.Build();  
      
    // Configure the HTTP request pipeline.  
    if (!app.Environment.IsDevelopment())  
    {  
        app.UseExceptionHandler("/Home/Error");  
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.  
        app.UseHsts();  
    }  
      
    app.UseHttpsRedirection();  
    app.UseStaticFiles();  
      
    app.UseRouting();  
      
    app.UseAuthorization();  
      
    app.UseSession();  
      
    app.MapRazorPages();  
    app.MapDefaultControllerRoute();  
      
    app.Run();  
    

    Saving data to Session

    public async Task<IActionResult> ParamIndex(string path = "/locations/england/southwest/exmouth/", string apiKey = "")  
    {  
        ViewBag.SrvDtTime = DateTime.Now.ToString("MM/dd/yyyy HH:mm");  
        int franchiseId = 0;  
        int.TryParse(apiKey, out franchiseId);  
        FranchiseWidgetSettingVM? windgetSetting = null;  
        if (!string.IsNullOrWhiteSpace(path) || !string.IsNullOrWhiteSpace(apiKey))  
        {  
            windgetSetting = /*await*/ FindFranchiseWidgetSettings(franchiseId, 0, apiKey, string.Empty, path);  
      
            //Cache FranchiseWidgetSettingVM in Session  
            HttpContext.Session.Set<FranchiseWidgetSettingVM>("Data", windgetSetting ?? new FranchiseWidgetSettingVM());  
        }  
           
        windgetSetting = (windgetSetting != null ? windgetSetting : new FranchiseWidgetSettingVM());  
        ParamPageModel item = new ParamPageModel() { ApiKey = apiKey, Path = path, Data = windgetSetting };  
      
        return Redirect("/parambooking/?path=" + item.Path + "&apikey=" + item.ApiKey);            
    }  
    

    Simplifying the Razor Page

    @page "/parambooking"  
    @model testapp.Pages.IndexModel  
      
    @{  
      
        DateTime curDateTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, 0);  
        DateTime serverStartDate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.AddDays(5).Day, 9, 0, 0);  
        DateTime serverEndDate = serverStartDate.AddDays(1);  
    }  
      
    <div>  
        FranchiseName: @Model.ParamPageModel?.Data?.FranchiseName  
    </div>  
    <div>  
        UpdatedDate: @Model.ParamPageModel?.Data?.UpdatedDate  
    </div>  
    <div>  
        TransactionDate: @Model.ParamPageModel?.Data?.TransactionDate  
    </div>  
    <div>  
        CustomApiUrl: @Model.ParamPageModel?.Data?.CustomApiUrl  
    </div>  
    

    Code

    using Microsoft.AspNetCore.Mvc;  
    using Microsoft.AspNetCore.Mvc.RazorPages;  
    using testapp.Models;  
    using testapp.Extensions;  
      
    namespace testapp.Pages  
    {  
        public class IndexModel : PageModel  
        {  
            [BindProperty]  
            public ParamPageModel? ParamPageModel { get; set; }  
      
            public void OnGet(string path, string apiKey)  
            {  
                FranchiseWidgetSettingVM? vm = HttpContext.Session.Get<FranchiseWidgetSettingVM>("Data");  
                ParamPageModel = new Models.ParamPageModel() { Path = path, ApiKey = apiKey, Data = vm };  
            }  
        }  
    }  
    

    Moving ViewModels to the Models fodler

    namespace testapp.Models  
    {  
        public class ParamPageModel  
        {  
            public string Path { get; set; } = "";  
            public string ApiKey { get; set; } = "";  
            public FranchiseWidgetSettingVM? Data { get; set; } = null!;  
        }  
      
        public class FranchiseWidgetSettingVM      
        {  
            public int Id { get; set; }  
            public int FranchiseId { get; set; }  
            public string? FranchiseName { get; set; }  
            public string ApiKey { get; set; } = null!;  
            public string WebSiteUrl { get; set; } = null!;  
            public string CustomApiUrl { get; set; } = null!;  
            public short StatusId { get; set; }  
            public DateTime? TransactionDate { get; set; }  
            public string? TransactionType { get; set; }  
            public DateTime? InsertedDate { get; set; }  
            public int? InsertedUserId { get; set; }  
            public string? InsertedUserName { get; set; }  
            public DateTime? UpdatedDate { get; set; }  
            public int? UpdateUserId { get; set; }  
            public string? UpdatedUserName { get; set; }  
      
        }  
    }  
    

    Using an extension method to handle serializing/deserializing session data.

    using System.Text.Json;  
      
    namespace testapp.Extensions  
    {  
        public static class SessionExtensions  
        {  
            public static void Set<T>(this ISession session, string key, T value)  
            {  
                session.SetString(key, JsonSerializer.Serialize(value));  
            }  
      
            public static T? Get<T>(this ISession session, string key)  
            {  
                var value = session.GetString(key);  
                return value == null ? default : JsonSerializer.Deserialize<T>(value);  
            }  
        }  
    }  
    

    Results

    FranchiseName: Fr1  
    UpdatedDate:  
    TransactionDate:  
    CustomApiUrl: /custom/contact/  
    
    1 person found this answer helpful.
    0 comments No comments