为什么 form method=post 重置数据实例?

问题描述

我正在尝试将图像 url 字符串添加数据库中访问者的 Badge 属性我有一个页面,我从数据库调用访问者的实例,然后从访问者那里格式化一些信息,对其进行截图,并生成一个图像 url。 OnGetAsync 工作正常,但是,我无法在 OnPostAsync 期间获取要发布到服务器的 url。我已经将问题缩小到表单标签,因为当我尝试使用表单标签 method=post 发布数据时,访问者的实例丢失了,因此 ModelState 无效(当表单标签删除时,url生成,所以我知道它不是 BadgeDataUrl 为空)。

为什么访问者实例会重置?我一直在搜索其他帖子,但没有看到任何人有类似的重置问题。我还尝试在 OnPostAsync 中再次设置访问者,但 ModelState 仍然无效,因为它将访问者的属性视为空(这很奇怪,因为当我为属性添加监视时,数据正确显示 - 我是不知道为什么 ModelState 是无效的)。

注册成功.cshtml.cs

public async Task<IActionResult> OnGetAsync(string visitorId)
{
    if (visitorId == null)
    {
        return NotFound();
    }
    Visitor = await _context.Visitor.FirstOrDefaultAsync(m => m.ID.ToString() == visitorId);
    if (Visitor == null)
    {
        return NotFound();
    }
    return Page();
}

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }
    //Badge processing
    var base64Badge = BadgeDataUrl.Split(",")[1];
    var binaryBadge = Convert.FromBase64String(base64Badge);
    System.IO.File.WriteallBytes("Badge.jpg",binaryBadge);
    Visitor.FutureBadge = BadgeDataUrl;
            
    _context.Attach(Visitor).State = EntityState.Modified;

    try
    {
        await _context.SaveChangesAsync();
    }
    catch (dbupdateConcurrencyException)
    {
        if (!VisitorExists(Visitor.ID))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    } 
    return RedirectToPage("/Visitors/RegistrationSuccess");
}
        
private bool VisitorExists(int id)
{
    return _context.Visitor.Any(e => e.ID == id);
}

注册成功.cshtml
@page "{visitorId}"
@model VisitorManagementSystem.Pages.Visitors.RegistrationSuccessModel
@{
}
@{
    ViewData["Title"] = "Success";
}

<head>
    <Meta charset="utf-8">
    <Meta name="viewport" content="width=device-width,initial-scale=1">
    <title>HTML TO IMAGE</title>
    <script src="https://html2canvas.hertzen.com/dist/html2canvas.js"></script>
    <script type="text/javascript">
        function downloadimage() {
            var container = document.getElementById("htmltoimage");; // full page
            html2canvas(container,{ allowTaint: true }).then(function (canvas) {
               var badgeData = canvas.toDataURL("image/jpeg");
                $('#BadgeDataUrl').val(badgeData);
            });
            }
    </script>
    <style>
        #htmltoimage {
            width: 65%;
            margin: auto;
        }
    </style>
</head>

<body>
    <form method="post">
        <br />
<div id="htmltoimage">
            <div id="badge" style=" Box-sizing: border-Box; background-color: white; border: 2px solid black; margin: 50px; padding: 0px; width: 10.15cm; height: 6.096cm">
                <div style="text-align:center; float:left; padding:0; float:left; vertical-align:top; background-color:red; color:white; font-family:Arial; font-size:25px; width:10.06cm">
                    <label>VISITOR</label>
                </div>
                <div style="float:left">
                    <img style="margin-left:18px; margin-top:13px; border:1px solid black; width: 3.2cm; height:2.4cm" src="@Model.Visitor.Picture" alt="Visitor Picture" />
                    <div style="text-align:left; margin-left:15px; margin-top:9px; line-height:0.8; font-size:13px; padding:5px;">
                        <label>CCI Host:</label><br>
                        <label id="destinationlabel">@Model.Visitor.Destination</label><br><br />
                    </div>
                </div>
                <div style="float:right; margin-top:3px; margin-right:7px; margin-bottom:0px; font-family: Arial; vertical-align:top">
                    <label id="datelabel">@Model.Visitor.DateCheckedIn.ToShortDateString()</label>
                </div>
                <div style="float:left; line-height:0.8; vertical-align:top">
                    <div style="font-size:45px; margin-top: 30px; line-height:0.1; margin-bottom:5px; margin-left:20px; margin-right:0; font-weight: bold;">@Model.Visitor.FirstName</div><br />
                    <div style="font-size:45px; margin-top: 5px; margin-bottom:10px; margin-left:20px; margin-right:0; font-weight: bold;">@Model.Visitor.LastName</div>
                    <label id="companynamelabel" style="font-size:18px; margin-left: 20px">@Model.Visitor.CompanyName</label><br>
                    <label id="titlelabel" style="font-size:18px; margin-left:20px">@Model.Visitor.CompanyTitle</label>
                </div>
                <div style="padding: 0px; margin: 0px; position: absolute; bottom: 0; left: 0; width: 10.05cm; background-color: red; color: white; font-family: Arial; font-size: 15px; text-align: right">
                    <label id="bottomredbar"></label>
                </div>
            </div>
        </div>
        <button type="submit" onclick="downloadimage()" class="clickbtn" id="downloadButton">Download/Print Badge</button><br />
        <div>
            @*This is here just to check if the url is generating*@
            <input asp-for="@Model.BadgeDataUrl">
        </div>
    </form>
</body>

我是新手,所以非常感谢您的帮助!



编辑
没有 ModelState 验证的 Registration.cshtml.cs:

public class RegistrationSuccessModel : PageModel
{
    [BindProperty]
    public Visitor Visitor { get; set; }

    [BindProperty]
    public string BadgeDataUrl { get; set; }

    private readonly VisitorManagementSystem.Data.VisitorManagementSystemContext _context;

    public RegistrationSuccessModel(VisitorManagementSystem.Data.VisitorManagementSystemContext context)
    {
        _context = context;
    }
    public async Task<IActionResult> OnGetAsync(string visitorId)
    {
        if (!string.IsNullOrEmpty(visitorId))
        {
            Visitor = _context.Set<Visitor>().FirstOrDefault(i => i.ID.ToString() == visitorId);
        }
        return Page();
    }

    public async Task<IActionResult> OnPostAsync(string visitorId)
    {
        Visitor = _context.Set<Visitor>().FirstOrDefault(i => i.ID.ToString() == visitorId);
        var base64Badge = BadgeDataUrl.Split(",")[1];
        var binaryBadge = Convert.FromBase64String(base64Badge);
        System.IO.File.WriteallBytes("Badge.jpg",binaryBadge);
        Visitor.FutureBadge = BadgeDataUrl;
            
        _context.Attach(Visitor).State = EntityState.Modified;

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (dbupdateConcurrencyException)
        {
            if (!VisitorExists(Visitor.ID))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToPage("/Visitors/RegistrationSuccess");
    } 
    private bool VisitorExists(int id)
    {
        return _context.Visitor.Any(e => e.ID == id);
    }
}

解决方法

  1. Visitor 值在 OnGet 方法中设置而不是全局设置。所以你不能把它保留在另一个请求中。此外,您使用 BindProperty 并且此属性用于绑定您场景中表单的值。

  2. 但是您使用了无法绑定到后端的标签元素。一种方法是您可以通过使用 jquery 获取元素值并通过 ajax 发布它们(如果您想在回发时执行任何操作,这将有点复杂)。另一种方法是为每个属性设置隐藏输入。

  3. 如果你使用 type="submit" 输入,它不会点击 onclick 事件。您需要更改为 type="button"

  4. html2canvas.js 的引用在我的项目中出错。所以我改成:

    <script src="https://cdn.jsdelivr.net/npm/html2canvas@1.1.4/dist/html2canvas.min.js"></script>
    

这是一个完整的工作演示:

Registration.cshtml:

<head>
    <script src="https://cdn.jsdelivr.net/npm/html2canvas@1.1.4/dist/html2canvas.min.js"></script>
    <script type="text/javascript">
        function downloadimage() {
            var container = document.getElementById("htmltoimage");; // full page
            html2canvas(container,{ allowTaint: true }).then(function (canvas) {
                var badgeData = canvas.toDataURL("image/jpeg");
                $('#BadgeDataUrl').val(badgeData);
                $('form').submit();  //add this...
            });
        }
    </script>       
</head>
<body>
    <form method="post">   //add hidden input to make form data post successfully....
        <input asp-for="Visitor.Destination" hidden />
        <input asp-for="Visitor.DateCheckedIn" hidden />
        <input asp-for="Visitor.FirstName" hidden />
        <input asp-for="Visitor.LastName" hidden />
        <input asp-for="Visitor.CompanyName" hidden />
        <input asp-for="Visitor.CompanyTitle" hidden />
        <input asp-for="Visitor.Picture" hidden />
        <br />
        <div id="htmltoimage">
            <div id="badge" style=" box-sizing: border-box; background-color: white; border: 2px solid black; margin: 50px; padding: 0px; width: 10.15cm; height: 6.096cm">
                <div style="text-align:center; float:left; padding:0; float:left; vertical-align:top; background-color:red; color:white; font-family:Arial; font-size:25px; width:10.06cm">
                    <label>VISITOR</label>
                </div>
                <div style="float:left">
                    <img style="margin-left:18px; margin-top:13px; border:1px solid black; width: 3.2cm; height:2.4cm" src="@Model.Visitor.Picture" alt="Visitor Picture" />
                    <div style="text-align:left; margin-left:15px; margin-top:9px; line-height:0.8; font-size:13px; padding:5px;">
                        <label>CCI Host:</label><br>
                        <label id="destinationlabel">@Model.Visitor.Destination</label><br><br />   
                    </div>
                </div>
                <div style="float:right; margin-top:3px; margin-right:7px; margin-bottom:0px; font-family: Arial; vertical-align:top">
                    <label id="datelabel">@Model.Visitor.DateCheckedIn.ToShortDateString()</label>    
                </div>
                <div style="float:left; line-height:0.8; vertical-align:top">
                    <div style="font-size:45px; margin-top: 30px; line-height:0.1; margin-bottom:5px; margin-left:20px; margin-right:0; font-weight: bold;">@Model.Visitor.FirstName</div><br />
                    <div style="font-size:45px; margin-top: 5px; margin-bottom:10px; margin-left:20px; margin-right:0; font-weight: bold;">@Model.Visitor.LastName</div>
                    <label id="companynamelabel" style="font-size:18px; margin-left: 20px">@Model.Visitor.CompanyName</label><br>
                    <label id="titlelabel" style="font-size:18px; margin-left:20px">@Model.Visitor.CompanyTitle</label>  
                </div>
                <div style="padding: 0px; margin: 0px; position: absolute; bottom: 0; left: 0; width: 10.05cm; background-color: red; color: white; font-family: Arial; font-size: 15px; text-align: right">
                    <label id="bottomredbar"></label>
                </div>
            </div>
        </div>
                   //change here....
        <button type="button" onclick="downloadimage()" class="clickbtn" id="downloadButton">Download/Print Badge</button><br />
        <div>
            <input asp-for="@Model.BadgeDataUrl">
        </div>
    </form>
</body>