MVC - 'Index' or its master was not found

2019-08-23 02:42发布

问题:

I am getting an error message that says:

Exception Details: System.InvalidOperationException: The view 'Index' or its 
master was not found or no view engine supports the searched locations. The 
following locations were searched:
~/Views/Request/Index.aspx
~/Views/Request/Index.ascx
~/Views/Shared/Index.aspx
~/Views/Shared/Index.ascx
~/Views/Request/1819.master
~/Views/Shared/1819.master
~/Views/Request/1819.cshtml
~/Views/Request/1819.vbhtml
~/Views/Shared/1819.cshtml
~/Views/Shared/1819.vbhtml

I've seen several different post about this but none of those answers have solved my problem. I tried clicking through the views in visual studio and it sends me to the appropriate methods. I tried adding a home controller with a home view and an Index but that does not help as well. I tried modifying my route config and that didn't work either.

Here is my return statement that is giving me issues:

return View("Index", requestVM.AidYear);

I am calling this method:

public ActionResult Index(string aidYear)

I tried this:

return View("Index", (object)requestVM.AidYear);

and I tried this:

return View("Index", model:requestVM.AidYear);

With the last 2 I get:

System.InvalidOperationException: The model item passed into the dictionary is of type 'System.String', but this dictionary requires a model item of type 'ScholarshipDisbursement.ViewModels.Request.RequestViewModel'.

This occurs on my local machine and on our production server. The team I'm on are sure that this was working when we published it because this is a pretty big issue to not have noticed so we aren't sure why it is no longer working. No changes have been made to production since we published this application so we know no one has done something to screw it up.

Just in case this helps here is my route config:

public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Request", action = "Index", id = UrlParameter.Optional }
        );
    }

Edit: In my view I have a folder Request and inside that folder is an Index.cshtml. On that view I have a form that submits to the method SubmitScholarshipRequest. That method is on the Request Controller.

In that method I run various checks and if there is an error I add it to the ModelState. If the ModelState is invalid I then:

return View("Index", requestVM.AidYear);

Otherwise I:

return RedirectToAction("Index", "Request", new { @aidYear = requestVM.AidYear });  

Here is my view:

@using ScholarshipDisbursement.Helpers
@using ScholarshipDisbursement.ViewModels.Request
@model RequestViewModel

@{
ViewBag.Title = "Scholarship Request";
Layout = "~/Views/Shared/_Layout.cshtml";
}

<div class="requestIndexRoundedShadow">

<div class="pageTitleHeader">
    <span><img src="~/Content/img/gradCap.ico" class="headerImg" /></span>
    <span class="headerTitle"><b>Scholarship Disbursement Request</b></span>
        <hr style="border-top: 1px solid black">

@using (Html.BeginForm("SubmitScholarshipRequest", "Request", 
FormMethod.Post, new { id = "SubmitTutorRequestFrm" }))
{
    @Html.AntiForgeryToken()

    <span id="aidYearLbl" Style="font-size: 14px;font-weight: bold">Academic 
Year: </span>
    @Html.DropDownListFor(m => m.AidYear, new SelectList(Model.AidYears, 
"Code", "Name"), new { id = "aidYear", onchange = "onChangeYear()", Style = 
"font-size: 14px" })

    if (Model.Scholarships.Any())
    {
        <br />
        <br />

        <table style="width: 100%;">
            <tr>
                <th class="headerBox tableHeader" colspan="3">Scholarships 
for @Model.User.DeptName</th>
            </tr>
            <tr>
                <th class="headerBox columnHeader" style="width: 
500px;">Scholarship Name</th>
                <th class="headerBox columnHeader" style="width: 
100px;">Amount</th>
                <th class="headerBox columnHeader" style="width: 
100px;">Requested</th>
            </tr>
            @{ int i = 1; }
            @foreach (var s in Model.Scholarships)
            {
                var rowColor = i % 2 == 0 ? "E8E8E8" : "ffffff";
                <tr style="background-color: #@rowColor;">
                    <td class="rowValue">@Html.ActionLink(s.Name, 
"ScholarshipRequest", "Request", new { aidYear = s.AidYear, fundCode = s.Id, 
}, new { target = "_blank" })</td>
                    <td class="rowValue">@s.AmountTotal</td>
                    <td class="rowValue">@s.AmountRequested</td>
                </tr>
                i++;
            }
        </table>

        <br />
        <br />

        if (Model.AvailScholarships.Any())
        {
            <table style="width: 100%">
                <tr>
                    <th class="headerBox tableHeader" colspan="6">Request 
Scholarship</th>
                </tr>
                <tr>
                    <th class="headerBox columnHeader">Scholarship</th>
                    <th class="headerBox columnHeader">Banner Id</th>
                    <th class="headerBox columnHeader">Student Name</th>
                    <th class="headerBox columnHeader">Amount</th>
                    <th class="headerBox columnHeader">Term</th>
                    <th class="headerBox columnHeader">Comments</th>
                </tr>
                <tr>
                    <td class="rowValue" style="width: 200px">@Html.DropDownListFor(m => m.ScholarshipId, new SelectList(Model.AvailScholarships, "Id", "Name"), "", new { id = "scholars" })</td>
                    <td class="rowValue" style="width: 125px">@Html.TextBoxFor(m => m.StudentId, new { autocomplete = "off", Style = "width:100%", id = "bannerId", maxlength = "9" })</td>
                    <td class="rowValue" style="width: 225px"><span id="studentName"></span></td>
                    <td class="rowValue" style="width: 50px">@Html.TextBoxFor(m => m.Amount, new { autocomplete = "off", Style = "width:100%", id = "amount", Value = "", data_val_number = " " })</td>
                    <td class="rowValue" style="width: 70px">@Html.DropDownListFor(m => m.Term, new SelectList(Model.Terms, "Code", "Name"), "", new { Style = "width:70px", id = "term" })</td>
                    <td class="rowValue" style="width: auto">@Html.TextBoxFor(m => m.Comments, new { autocomplete = "off", Style = "width:100%", id = "comments" })</td>
                </tr>
                <tr>
                    <td>@Html.ValidationMessageFor(m => m.ScholarshipId)</td>
                    <td>@Html.ValidationMessageFor(m => m.StudentId)</td>
                    <td></td>
                    <td>@Html.ValidationMessageFor(m => m.Amount)</td>
                    <td>@Html.ValidationMessageFor(m => m.Term)</td>
                    <td>@Html.ValidationMessageFor(m => m.Comments)</td>
                </tr>
            </table>

            <br />
            <input type="submit" id="SubmitNomineeBtn" name="SubmitNomineeBtn" class="submitButton" value="Submit" />
            <span id="warning"></span>
            <br />
            <br />
            <div class="field-validation-error">
                @Html.ErrorFor(ViewData, "ExceedsAmountError")
            </div>
            <div class="field-validation-error">
                @Html.ErrorFor(ViewData, "DuplicateEntryError")
            </div>
            <div class="field-validation-error">
                @Html.ErrorFor(ViewData, "NullStudent")
            </div>
            <div class="field-validation-error">
                @Html.ErrorFor(ViewData, "NegativeAmount")
            </div>
        }
        else
        {
            <div style="padding-right: 100px">
                <img src="~/Content/img/alert.png" /> There are currently no funds available for the @Model.User.DeptName department.
            </div>
        }

    }
    else
    {
        <br />
        <br />
        <div style="padding-right: 100px">
            <img src="~/Content/img/alert.png" /> There are currently no scholarships available for the @Model.User.DeptName department.
        </div>
    }
}



</div>

<script>

$('#help').click(function() {
    var win = $('#window').data("kendoWindow");
    win.open();
    win.center();
    win.top();
});

$(document).ready(function () {   
    if ($('#bannerId').val()) {
        checkBannerId(); 
    }
});

function checkBannerId() {
    var student = $('#bannerId').val();
    $.ajax({
        type: "POST",
        url: '@Url.Action("GetStudentName","Request")',
        contentType: "application/json; charset=utf-8",
        data: JSON.stringify({ bannerId: student }),  // parameter aNumber
        dataType: "json",
        success: function (msg) {
            if (msg.Result === "Null Student") {
                $('#studentName').html("Error finding student name");
                $('#studentName').css("color", "red");
                $('#bannerId').css("border-color", "red");
                $('#bannerId').css("color", "red");
                $('#warning').html("Invalid Banner Id.");
                $('#warning').css('color', 'red');

                return;
            } else {
                $('#bannerId').css("border-color", "unset");
                $('#bannerId').css("color", "black");
                $('#studentName').html(msg.Result);
                $('#studentName').css('color', 'black');
                $('#warning').html("");
                $('#warning').css('color', 'unset');
            }
        },
        error: function () {
        }
    });
}

function onChangeYear() {
    window.location = '@Url.Action("Index", "Request")?aidYear=' + $("#aidYear").val();
}

$('#amount').blur(function () {
    if (isNaN($('#amount').val()) || $('#amount').val() < 0) {
        $('#warning').html("Invalid amount ($, commas, and negative numbers not allowed).");
        $('#warning').css('color', 'red');
        $('#amount').css("border-color", "red");
        $('#amount').css('color', "red");
    } else {
        $('#amount').css("border-color", "unset");
        $('#amount').css("color", "unset");
        $('#warning').html("");
        $('#warning').css('color', 'unset');
    }
});    

$('#bannerId').blur(function () {
    checkBannerId();
});

</script>

Here is the method the form calls:

[HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult SubmitScholarshipRequest(RequestViewModel requestVM)
    {
        var scholarshipMgr = new ScholarshipStore();
        var scholarship = scholarshipMgr.GetScholarship(requestVM.ScholarshipId, requestVM.AidYear);
        double amountTotal = scholarship.AmountTotal;
        double amountRequested = scholarship.AmountRequested;
        double addTotal = amountRequested + requestVM.Amount;

        string username = User.Identity.Name;
        var user = new UserStore().GetUser(username);

        var student = new StudentStore().GetStudent(requestVM.StudentId);

        if (student == null)
        {
            ModelState.AddModelError("NullStudent","Unable to find Student");
        }

        var scholarshipRequestMgr = new ScholarshipRequestStore();

        var scholarshipRequest = scholarshipRequestMgr.GetScholarshipRequest(requestVM.StudentId, requestVM.ScholarshipId, requestVM.AidYear);

        if (scholarshipRequest != null)
        {
            ModelState.AddModelError("DuplicateEntryError", "Scholarship already requested for this student!");
        }

        if (addTotal > amountTotal)
        {
            ModelState.AddModelError("ExceedsAmountError", "Amount entered exceeds the total available!");
        }

        if (addTotal < 0)
        {
            ModelState.AddModelError("NegativeAmount", "Must be a positive number");
        }

        if (!ModelState.IsValid)
        {
            var aidYears = new AidYearStore().GetAidYears();
            var scholarships = new ScholarshipStore().GetScholarships(user.DeptCode, requestVM.AidYear);
            var availableScholarships = scholarships.Where(x => x.AmountTotal > x.AmountRequested);
            var terms = new TermStore().GetAllTerms();

            requestVM.AidYears = aidYears;
            requestVM.User = user;
            requestVM.Scholarships = scholarships;
            requestVM.AvailScholarships = availableScholarships;
            requestVM.Terms = terms;

            return View("Index", requestVM.AidYear);
        }

        var scholarShipRequest = new ScholarshipRequest
        {
            AidYear = requestVM.AidYear,
            ScholarshipId = requestVM.ScholarshipId,
            StudentId = requestVM.StudentId,
            Amount = requestVM.Amount,
            TermCode = requestVM.Term,
            Comments = requestVM.Comments,
            DeptId = user.DeptCode,
            DateCreated = DateTime.Now,
            CreatedBy = username,
            PIDM = new StudentStore().GetStudent(requestVM.StudentId).PIDM
        };

        new ScholarshipRequestStore().CreateScholarshipRequest(scholarShipRequest);

        return RedirectToAction("Index", "Request", new { @aidYear = requestVM.AidYear });

    }

Here is the Index View Method from the RequestController:

public ActionResult Index(string aidYear)
    {
        aidYear = string.IsNullOrEmpty(aidYear) ? new FinAidYear().GetCurrentYear() : aidYear;

        string username = User.Identity.Name;
        if (!Authorization.CheckUsernameDept(username))           
            return RedirectToAction("NotAuthorized", "Account");

        var user = new UserStore().GetUser(username);
        var aidYears = new AidYearStore().GetAidYears();
        var scholarships = new ScholarshipStore().GetScholarships(user.DeptCode, aidYear);
        var availableScholarships = scholarships.Where(x => x.AmountTotal > x.AmountRequested);
        var terms = new TermStore().GetAllTerms();

        var requestVM = new RequestViewModel
        {
            AidYear = aidYear,
            AidYears = aidYears,
            User = user,
            Scholarships = scholarships,
            AvailScholarships = availableScholarships,
            Terms = terms
        };

        return View(requestVM);
    }

回答1:

Your view expects a RequestViewModel, not a string. So giving it just the aid year will not work. That's what the "Index" action method expects, but here we're just loading the view directly, not executing the action method (after all, we're already executing a different action method). So you need to pass the whole viewmodel object in the return statement.

Additionally, because it's not an action method called "Index", you'll need to specify the name of the view you want to return.

I would expect that

return View("Index", requestVM);

would solve your problem.



回答2:

It seems your view has the header :

@model ScholarshipDisbursement.ViewModels.Request.RequestViewModel

So, you should use that :

return View(requestVM);

For the application is expected all the viewModel.

Otherwise, we will need your structure for a better help.



回答3:

I think the clue is in the error message. It's looking for a view named 1819.cshtml.

This is telling it to look for a view with the value of requestVM.AidYear to use for the master or template page.

return View("Index", requestVM.AidYear);

If you wanted to pass a model to the view use this instead. Instead of a string (which I assume requestVM.AidYear is) I'm passing something that's not a string. So it'll use requestVM as the model.

return View("Index", requestVM);

Alternatively, this may be what you want. to use

return RedirectToAction("Index", "Request", new { @aidYear = requestVM.AidYear });