【问题标题】:'object' does not contain a definition for 'Action' when using IdentityUser with OAuth将 IdentityUser 与 OAuth 一起使用时,“对象”不包含“操作”的定义
【发布时间】:2013-12-09 14:42:21
【问题描述】:

我不确定这是如何或为什么会发生的,但在 google 和 stackoverflow 上花了一天时间后,我需要一些帮助来了解问题所在。

这是错误...

Server Error in '/' Application.

    'object' does not contain a definition for 'Action'

    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

    Exception Details: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'object' does not contain a definition for 'Action'

    Source Error: 


    Line 15:     else
    Line 16:     {
    Line 17:         string action = **Model.Action**;
    Line 18:         string returnUrl = Model.ReturnUrl;
    Line 19:         using (Html.BeginForm(action, "Account", new { ReturnUrl = returnUrl }))

    Source File: c:\Users\Developer\Source\Repos\Zenwire-Master\Zenwire\Views\Account\_ExternalLoginsListPartial.cshtml    Line: 17 

~/Controllers/AccountController

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Owin.Security;
using Zenwire.Models;

namespace Zenwire.Controllers
{
    [Authorize]
    public class AccountController : Controller
    {
        public AccountController()
            : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new IdentityDbContext())))
        {
        }

        public AccountController(UserManager<ApplicationUser> userManager)
        {
            UserManager = userManager;
        }

        public UserManager<ApplicationUser> UserManager { get; private set; }

        //
        // GET: /Account/Login
        [AllowAnonymous]
        public ActionResult Login(string returnUrl)
        {
            ViewBag.ReturnUrl = returnUrl;
            return View();
        }

        //
        // POST: /Account/Login
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                var user = await UserManager.FindAsync(model.UserName, model.Password);
                if (user != null)
                {
                    await SignInAsync(user, model.RememberMe);
                    return RedirectToLocal(returnUrl);
                }
                else
                {
                    ModelState.AddModelError("", "Invalid username or password.");
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

        //
        // GET: /Account/Register
        [AllowAnonymous]
        public ActionResult Register()
        {
            return View();
        }

        //
        // POST: /Account/Register
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Register(RegisterViewModel model)
        {
            if (ModelState.IsValid)
            {
                var user = new ApplicationUser()
                {
                    UserName = model.UserName,
                    FirstName = model.FirstName,
                    LastName = model.LastName,
                    Address = model.Address,
                    City = model.City,
                    PostalCode = model.PostalCode,
                    Province = model.Province,
                    Phone = model.Phone,
                    Email = model.Email
                };

                var result = await UserManager.CreateAsync(user, model.Password);
                if (result.Succeeded)
                {
                    await SignInAsync(user, isPersistent: false);
                    return RedirectToAction("Index", "Home");
                }
                else
                {
                    AddErrors(result);
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

        //
        // POST: /Account/Disassociate
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Disassociate(string loginProvider, string providerKey)
        {
            ManageMessageId? message = null;
            IdentityResult result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(), new UserLoginInfo(loginProvider, providerKey));
            if (result.Succeeded)
            {
                message = ManageMessageId.RemoveLoginSuccess;
            }
            else
            {
                message = ManageMessageId.Error;
            }
            return RedirectToAction("Manage", new { Message = message });
        }

        //
        // GET: /Account/Manage
        public ActionResult Manage(ManageMessageId? message)
        {
            ViewBag.StatusMessage =
                message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
                : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
                : message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
                : message == ManageMessageId.Error ? "An error has occurred."
                : "";
            ViewBag.HasLocalPassword = HasPassword();
            ViewBag.ReturnUrl = Url.Action("Manage");
            return View();
        }

        //
        // POST: /Account/Manage
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Manage(ManageUserViewModel model)
        {
            bool hasPassword = HasPassword();
            ViewBag.HasLocalPassword = hasPassword;
            ViewBag.ReturnUrl = Url.Action("Manage");
            if (hasPassword)
            {
                if (ModelState.IsValid)
                {
                    IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword, model.NewPassword);
                    if (result.Succeeded)
                    {
                        return RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess });
                    }
                    else
                    {
                        AddErrors(result);
                    }
                }
            }
            else
            {
                // User does not have a password so remove any validation errors caused by a missing OldPassword field
                ModelState state = ModelState["OldPassword"];
                if (state != null)
                {
                    state.Errors.Clear();
                }

                if (ModelState.IsValid)
                {
                    IdentityResult result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword);
                    if (result.Succeeded)
                    {
                        return RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess });
                    }
                    else
                    {
                        AddErrors(result);
                    }
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

        //
        // POST: /Account/ExternalLogin
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult ExternalLogin(string provider, string returnUrl)
        {
            // Request a redirect to the external login provider
            return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
        }

        //
        // GET: /Account/ExternalLoginCallback
        [AllowAnonymous]
        public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
        {
            var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
            if (loginInfo == null)
            {
                return RedirectToAction("Login");
            }

            // Sign in the user with this external login provider if the user already has a login
            var user = await UserManager.FindAsync(loginInfo.Login);
            if (user != null)
            {
                await SignInAsync(user, isPersistent: false);
                return RedirectToLocal(returnUrl);
            }
            else
            {
                // If the user does not have an account, then prompt the user to create an account
                ViewBag.ReturnUrl = returnUrl;
                ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
                return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { UserName = loginInfo.DefaultUserName });
            }
        }

        //
        // POST: /Account/LinkLogin
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult LinkLogin(string provider)
        {
            // Request a redirect to the external login provider to link a login for the current user
            return new ChallengeResult(provider, Url.Action("LinkLoginCallback", "Account"), User.Identity.GetUserId());
        }

        //
        // GET: /Account/LinkLoginCallback
        public async Task<ActionResult> LinkLoginCallback()
        {
            var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId());
            if (loginInfo == null)
            {
                return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
            }
            var result = await UserManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login);
            if (result.Succeeded)
            {
                return RedirectToAction("Manage");
            }
            return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
        }

        //
        // POST: /Account/ExternalLoginConfirmation
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl)
        {
            if (User.Identity.IsAuthenticated)
            {
                return RedirectToAction("Manage");
            }

            if (ModelState.IsValid)
            {
                // Get the information about the user from the external login provider
                var info = await AuthenticationManager.GetExternalLoginInfoAsync();
                if (info == null)
                {
                    return View("ExternalLoginFailure");
                }
                var user = new ApplicationUser()
                {
                    UserName = model.UserName,
                    FirstName = model.FirstName,
                    LastName = model.LastName,
                    Address = model.Address,
                    City = model.City,
                    PostalCode = model.PostalCode,
                    Province = model.Province,
                    Phone = model.Phone,
                    Email = model.Email
                };

                var result = await UserManager.CreateAsync(user);
                if (result.Succeeded)
                {
                    result = await UserManager.AddLoginAsync(user.Id, info.Login);
                    if (result.Succeeded)
                    {
                        await SignInAsync(user, isPersistent: false);
                        return RedirectToLocal(returnUrl);
                    }
                }
                AddErrors(result);
            }

            ViewBag.ReturnUrl = returnUrl;
            return View(model);
        }

        //
        // POST: /Account/LogOff
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult LogOff()
        {
            AuthenticationManager.SignOut();
            return RedirectToAction("Index", "Home");
        }

        //
        // GET: /Account/ExternalLoginFailure
        [AllowAnonymous]
        public ActionResult ExternalLoginFailure()
        {
            return View();
        }

        [ChildActionOnly]
        public ActionResult RemoveAccountList()
        {
            var linkedAccounts = UserManager.GetLogins(User.Identity.GetUserId());
            ViewBag.ShowRemoveButton = HasPassword() || linkedAccounts.Count > 1;
            return (ActionResult)PartialView("_RemoveAccountPartial", linkedAccounts);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing && UserManager != null)
            {
                UserManager.Dispose();
                UserManager = null;
            }
            base.Dispose(disposing);
        }

        #region Helpers
        // Used for XSRF protection when adding external logins
        private const string XsrfKey = "XsrfId";

        private IAuthenticationManager AuthenticationManager
        {
            get
            {
                return HttpContext.GetOwinContext().Authentication;
            }
        }

        private async Task SignInAsync(ApplicationUser user, bool isPersistent)
        {
            AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
            var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
            AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
        }

        private void AddErrors(IdentityResult result)
        {
            foreach (var error in result.Errors)
            {
                ModelState.AddModelError("", error);
            }
        }

        private bool HasPassword()
        {
            var user = UserManager.FindById(User.Identity.GetUserId());
            if (user != null)
            {
                return user.PasswordHash != null;
            }
            return false;
        }

        public enum ManageMessageId
        {
            ChangePasswordSuccess,
            SetPasswordSuccess,
            RemoveLoginSuccess,
            Error
        }

        private ActionResult RedirectToLocal(string returnUrl)
        {
            if (Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }

        private class ChallengeResult : HttpUnauthorizedResult
        {
            public ChallengeResult(string provider, string redirectUri)
                : this(provider, redirectUri, null)
            {
            }

            public ChallengeResult(string provider, string redirectUri, string userId)
            {
                LoginProvider = provider;
                RedirectUri = redirectUri;
                UserId = userId;
            }

            public string LoginProvider { get; set; }
            public string RedirectUri { get; set; }
            public string UserId { get; set; }

            public override void ExecuteResult(ControllerContext context)
            {
                var properties = new AuthenticationProperties() { RedirectUri = RedirectUri };
                if (UserId != null)
                {
                    properties.Dictionary[XsrfKey] = UserId;
                }
                context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
            }
        }
        #endregion
    }
}

~/查看

@using Microsoft.Owin.Security
<h4>Use another service to log in.</h4>
<hr />
@{
    var loginProviders = Context.GetOwinContext().Authentication.GetExternalAuthenticationTypes();
    if (loginProviders.Count() == 0)
    {
        <div>
            <p>
                There are no external authentication services configured. See <a href="http://go.microsoft.com/fwlink/?LinkId=313242">this article</a>
                for details on setting up this ASP.NET application to support logging in via external services.
            </p>
        </div>
    }
    else
    {
        string action = Model.Action;
        string returnUrl = Model.ReturnUrl;
        using (Html.BeginForm(action, "Account", new { ReturnUrl = returnUrl }))
        {
            @Html.AntiForgeryToken()
            <div id="socialLoginList">
                <p>
                    @foreach (AuthenticationDescription p in loginProviders)
                    {
                        <button type="submit" class="btn btn-default" id="@p.AuthenticationType" name="provider" value="@p.AuthenticationType" title="Log in using your @p.Caption account">@p.AuthenticationType</button>
                    }
                </p>
            </div>
        }
    }
}

~/Models/IdentityModels

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using Microsoft.AspNet.Identity.EntityFramework;

namespace Zenwire.Models
{
    // You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
    public class ApplicationUser : IdentityUser
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Address { get; set; }
        public string City { get; set; }
        public string Province { get; set; }
        public string PostalCode { get; set; }

        [DataType(DataType.PhoneNumber)]
        public string Phone { get; set; }

        [DataType(DataType.EmailAddress)]
        public string Email { get; set; }

        public virtual string Fullname { get { return FirstName + " " + LastName; } }
    }
}

~/App_Start/IdentityConfig

using Zenwire.Models;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using Zenwire.Repositories;

namespace Zenwire
{
    public class IdentityInitializer : DropCreateDatabaseAlways<ZenwireContext>
    {
        protected override void Seed(ZenwireContext context)
        {
            var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
            var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));

            const string username = "Admin";
            const string password = "123456";

            //Create Role
            roleManager.Create(new IdentityRole("Admin"));
            userManager.Create(new ApplicationUser() { UserName = username });

            //Create Role Admin if it does not exist
            if (!roleManager.RoleExists("Admin"))
            {
                roleManager.Create(new IdentityRole("Admin"));
            }

            //Create User=Admin with password=123456
            var user = new ApplicationUser { UserName = username };
            var adminresult = userManager.Create(user, password);

            //Add User Admin to Role Admin
            if (adminresult.Succeeded)
            {
                userManager.AddToRole(user.Id, username);
            }

            base.Seed(context);
        }
    }
}

【问题讨论】:

  • 我刚才也发生了同样的事情。不过,我无法向 Connect 问题提交任何内容。它说我在顶部登录,但退出了 cmets。当我点击登录时,什么也没有发生……一个被窃听的 bugtracker。真的很棒

标签: c# oauth-2.0 asp.net-mvc-5


【解决方案1】:

好的,这在我的项目中确实令人沮丧。从 ExternalLoginConfirmationViewModel 模型中删除属性后,我得到了同样的错误。

原来是ExternalLoginConfirmationViewModel.cshtm有错误,并没有停止构建进度,只在错误列表窗口中显示一次,然后所有这些错误都消失了,并在一段时间后随机出现。

确保您没有引用 ExternalLoginConfirmationViewModel.cshtm 中不存在的属性

这样:

 <div class="form-group">
        @Html.LabelFor(m => m.HomeTown, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.HomeTown, new { @class = "form-control" })
            @Html.ValidationMessageFor(m => m.HomeTown)
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.BirthDate, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.BirthDate, new { @class = "form-control" })
            @Html.ValidationMessageFor(m => m.BirthDate)
        </div>
    </div>   

【讨论】:

    【解决方案2】:

    根据 Microsoft https://connect.microsoft.com/VisualStudio/feedback/details/813133/bug-in-mvc-5-framework-asp-net-identity-modules,此问题现在似乎已修复

    就我个人而言,我使用 NuGet:Update-Package 解决了我解决方案中所有包的问题。我附上了packages.config的前后供参考。

    【讨论】:

      【解决方案3】:

      这个问题似乎随机出现在 MVC 5 项目中。到目前为止,我无缘无故地停止允许在局部视图中使用动态/匿名类型。

      我刚刚遇到了同样的问题,_ExternalLoginsListPartial.cshtml 页面甚至回滚添加的项目更改也没有任何区别。一旦坏了,它似乎就一直坏了。

      目前唯一的解决方案是不使用匿名类型,而是添加具有所需属性的强类型类。

      例如像这样添加一个新类:

      namespace Project.Models
      {
          public class ExternalLoginViewModel
          {
              public string Action { get; set; }
              public string ReturnUrl { get; set; }
          }
      }
      

      并在部分视图中引用它

      @model Project.Models.ExternalLoginViewModel

      以及渲染局部视图的位置,更改为:

      @Html.Partial("_ExternalLoginsListPartial", new Project.Models.ExternalLoginViewModel() { Action = "ExternalLogin", ReturnUrl = ViewBag.ReturnUrl })
      

      【讨论】:

      • 这实际上是一个非常好的方法。我最终做了一个 expando 对象来处理它。
      • 你为我节省了一些时间和头发!
      • 这个问题在以后的版本中修复了吗?是否已向 M$ 报告?
      • @PussInBoots:我正在使用截至今天(2014 年 1 月 6 日)的最新版本,但在一个项目中仍然存在这个问题。似乎不可能故意复制,这使得报告变得困难。
      • 1 月 30 日仍然发生在我身上。
      【解决方案4】:

      在局部视图中使用动态类型时,我经常会遇到这种情况。

      处理它的最简单方法是清理您的解决方案并重新构建。

      【讨论】:

      • 这对我有用。将本地 .git 存储库从一个驱动器移动到另一个驱动器后,我开始遇到同样的错误。清理我的解决方案并重新构建就可以了!
      【解决方案5】:

      这可能看起来很傻,但这是我所拥有的......

      我启动了一个 Web 应用程序,它的外部登录功能在 google、facebook 和 twitter 上运行良好,然后我决定登录按钮应该看起来很漂亮,所以我使用了以下链接: http://www.beabigrockstar.com/pretty-social-login-buttons-for-asp-net-mvc-5/

      之后我遇到了这个奇怪的错误(对象不包含动作定义)并来到这篇文章..

      首先我尝试了 TrueBlueAussie 解决方案,但对我不起作用,然后我尝试了 Antonio Chagoury..

      然后我在动作上放了一个断点:

      public ActionResult ExternalLogin(string provider, string returnUrl)
      

      然后将鼠标悬停在 provider 上,它显示 null ??当我点击 facebook 或 twitter 等时..

      所以我回到 _ExternalLoginsListPartial 视图上的按钮并查看按钮,发现 name 属性有一个多余的空格:

      name=" provider" value="@p.AuthenticationType"
      

      删除那个空间对我有用!

      name="provider" value="@p.AuthenticationType"
      

      我不知道我是怎么在“提供者”这个词之前得到那个多余的空间

      但是..我学到的教训是,在您遇到长时间的故障排除之前,您应该一丝不苟,仔细考虑简单的原因..

      我希望这将帮助那些一直拉扯头发的人发现这只是一个拼写错误:P

      【讨论】:

      • 虽然这可能会回答您自己的问题版本(显然其他解决方案都无法解决您的错字),但我怀疑其他人是否会将相同的 额外空间添加到nameproperty 问题:) 谢谢你提到它。
      【解决方案6】:

      【讨论】:

      • 请分享您的来源?
      • 抱歉,我发的时候太着急了。现已更新源代码。
      【解决方案7】:

      我遇到了同样的问题,我可以通过删除应用程序的 bin/ 和 obj/ 文件夹来解决问题。

      这会让你继续前进,但我喜欢@TrueBlueAussie 的想法,虽然我还没有尝试过。

      【讨论】:

      • 快速干净。谢谢
      • 清除 bin 和 obj 文件夹在这里似乎没有帮助:(
      【解决方案8】:

      您的应用程序在名为_ExternalLoginsListPartial 的局部视图中引发异常。它抛出是因为局部视图已使用不具有称为 Action 的预期属性的模型进行实例化。 此部分包含在从默认 mvc 项目模板创建的项目的登录视图中。

      它是这样包含的:

              @Html.Partial("_ExternalLoginsListPartial", new { Action = "ExternalLogin", ReturnUrl = ViewBag.ReturnUrl })
      

      在您的应用程序中,_ExternalLoginsListPartial 部分包含在某处,而没有传递具有 Action 属性的模型。 您可以搜索所有视图以查找您可能包含 _ExternalLoginsListPartial 的所有位置,并确保始终将有效模型传递给部分。

      【讨论】:

      • 这个问题似乎在 MVC 5 项目中无缘无故发生,一旦发生,部分视图将停止接受动态/匿名对象。到目前为止,唯一的解决方法是添加强类型模型(请参阅我的替代答案)。
      • 是的,虽然您认为这是正确的,但我可以在调用堆栈中看到我的调用来自一个调用站点,并创建了正确的匿名对象,并且当我提示 Model 变量时它报告它是一个具有正确属性的匿名对象,但同样抛出异常。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-25
      • 2011-02-20
      • 1970-01-01
      • 2013-08-27
      • 1970-01-01
      相关资源
      最近更新 更多