我在.net和NUGet中发现的令人讨厌的事情之一就是我永远不知道默认情况下安装了什么版本的东西.当尝试向现有项目添加内容时,这可能会非常令人沮丧.....
这是我目前的困境.
我有一个只有MVC的MVC 5项目.这个项目非常庞大,将其转移到另一个项目的工作需要花费太多时间.所以,我打开了NUGet并输入了WebApi并安装了它.
然后我创建了一个空白的WebApi项目,其中设置了个人帐户,并将StartUp代码复制到我当前的StartUp以及所需的任何其他配置中.
然后我开始创建我的AccountController,它直接从我创建的干净项目中复制.它看起来像这样:
[Authorize] [RoutePrefix("api/Account")] public class AccountController : ApiController { private const string LocalLoginProvider = "Local"; public AccountController() : this(Startup.UserManagerFactory(), Startup.OAuthOptions.AccessTokenFormat) { } public AccountController(UserManageruserManager, ISecureDataFormat accessTokenFormat) { UserManager = userManager; AccessTokenFormat = accessTokenFormat; } public UserManager UserManager { get; private set; } public ISecureDataFormat AccessTokenFormat { get; private set; } // GET api/Account/UserInfo [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)] [Route("UserInfo")] public UserInfoViewModel GetUserInfo() { ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity); return new UserInfoViewModel { UserName = User.Identity.GetUserName(), HasRegistered = externalLogin == null, LoginProvider = externalLogin != null ? externalLogin.LoginProvider : null }; } // POST api/Account/Logout [Route("Logout")] public IHttpActionResult Logout() { Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType); return Ok(); } // GET api/Account/ManageInfo?returnUrl=%2F&generateState=true [Route("ManageInfo")] public async Task GetManageInfo(string returnUrl, bool generateState = false) { IdentityUser user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); if (user == null) { return null; } List logins = new List (); foreach (IdentityUserLogin linkedAccount in user.Logins) { logins.Add(new UserLoginInfoViewModel { LoginProvider = linkedAccount.LoginProvider, ProviderKey = linkedAccount.ProviderKey }); } if (user.PasswordHash != null) { logins.Add(new UserLoginInfoViewModel { LoginProvider = LocalLoginProvider, ProviderKey = user.UserName, }); } return new ManageInfoViewModel { LocalLoginProvider = LocalLoginProvider, UserName = user.UserName, Logins = logins, ExternalLoginProviders = GetExternalLogins(returnUrl, generateState) }; } // POST api/Account/ChangePassword [Route("ChangePassword")] public async Task ChangePassword(ChangePasswordBindingModel model) { if (!ModelState.IsValid) { return BadRequest(ModelState); } IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword, model.NewPassword); IHttpActionResult errorResult = GetErrorResult(result); if (errorResult != null) { return errorResult; } return Ok(); } // POST api/Account/SetPassword [Route("SetPassword")] public async Task SetPassword(SetPasswordBindingModel model) { if (!ModelState.IsValid) { return BadRequest(ModelState); } IdentityResult result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword); IHttpActionResult errorResult = GetErrorResult(result); if (errorResult != null) { return errorResult; } return Ok(); } // POST api/Account/AddExternalLogin [Route("AddExternalLogin")] public async Task AddExternalLogin(AddExternalLoginBindingModel model) { if (!ModelState.IsValid) { return BadRequest(ModelState); } Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie); AuthenticationTicket ticket = AccessTokenFormat.Unprotect(model.ExternalAccessToken); if (ticket == null || ticket.Identity == null || (ticket.Properties != null && ticket.Properties.ExpiresUtc.HasValue && ticket.Properties.ExpiresUtc.Value < DateTimeOffset.UtcNow)) { return BadRequest("External login failure."); } ExternalLoginData externalData = ExternalLoginData.FromIdentity(ticket.Identity); if (externalData == null) { return BadRequest("The external login is already associated with an account."); } IdentityResult result = await UserManager.AddLoginAsync(User.Identity.GetUserId(), new UserLoginInfo(externalData.LoginProvider, externalData.ProviderKey)); IHttpActionResult errorResult = GetErrorResult(result); if (errorResult != null) { return errorResult; } return Ok(); } // POST api/Account/RemoveLogin [Route("RemoveLogin")] public async Task RemoveLogin(RemoveLoginBindingModel model) { if (!ModelState.IsValid) { return BadRequest(ModelState); } IdentityResult result; if (model.LoginProvider == LocalLoginProvider) { result = await UserManager.RemovePasswordAsync(User.Identity.GetUserId()); } else { result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(), new UserLoginInfo(model.LoginProvider, model.ProviderKey)); } IHttpActionResult errorResult = GetErrorResult(result); if (errorResult != null) { return errorResult; } return Ok(); } // GET api/Account/ExternalLogin [OverrideAuthentication] [HostAuthentication(DefaultAuthenticationTypes.ExternalCookie)] [AllowAnonymous] [Route("ExternalLogin", Name = "ExternalLogin")] public async Task GetExternalLogin(string provider, string error = null) { if (error != null) { return Redirect(Url.Content("~/") + "#error=" + Uri.EscapeDataString(error)); } if (!User.Identity.IsAuthenticated) { return new ChallengeResult(provider, this); } ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity); if (externalLogin == null) { return InternalServerError(); } if (externalLogin.LoginProvider != provider) { Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie); return new ChallengeResult(provider, this); } IdentityUser user = await UserManager.FindAsync(new UserLoginInfo(externalLogin.LoginProvider, externalLogin.ProviderKey)); bool hasRegistered = user != null; if (hasRegistered) { Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie); ClaimsIdentity oAuthIdentity = await UserManager.CreateIdentityAsync(user, OAuthDefaults.AuthenticationType); ClaimsIdentity cookieIdentity = await UserManager.CreateIdentityAsync(user, CookieAuthenticationDefaults.AuthenticationType); AuthenticationProperties properties = ApplicationOAuthProvider.CreateProperties(user.UserName); Authentication.SignIn(properties, oAuthIdentity, cookieIdentity); } else { IEnumerable claims = externalLogin.GetClaims(); ClaimsIdentity identity = new ClaimsIdentity(claims, OAuthDefaults.AuthenticationType); Authentication.SignIn(identity); } return Ok(); } // GET api/Account/ExternalLogins?returnUrl=%2F&generateState=true [AllowAnonymous] [Route("ExternalLogins")] public IEnumerable GetExternalLogins(string returnUrl, bool generateState = false) { IEnumerable descriptions = Authentication.GetExternalAuthenticationTypes(); List logins = new List (); string state; if (generateState) { const int strengthInBits = 256; state = RandomOAuthStateGenerator.Generate(strengthInBits); } else { state = null; } foreach (AuthenticationDescription description in descriptions) { ExternalLoginViewModel login = new ExternalLoginViewModel { Name = description.Caption, Url = Url.Route("ExternalLogin", new { provider = description.AuthenticationType, response_type = "token", client_id = Startup.PublicClientId, redirect_uri = new Uri(Request.RequestUri, returnUrl).AbsoluteUri, state = state }), State = state }; logins.Add(login); } return logins; } // POST api/Account/Register [AllowAnonymous] [Route("Register")] public async Task Register(RegisterBindingModel model) { if (!ModelState.IsValid) { return BadRequest(ModelState); } IdentityUser user = new IdentityUser { UserName = model.UserName }; IdentityResult result = await UserManager.CreateAsync(user, model.Password); IHttpActionResult errorResult = GetErrorResult(result); if (errorResult != null) { return errorResult; } return Ok(); } // POST api/Account/RegisterExternal [OverrideAuthentication] [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)] [Route("RegisterExternal")] public async Task RegisterExternal(RegisterExternalBindingModel model) { if (!ModelState.IsValid) { return BadRequest(ModelState); } ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity); if (externalLogin == null) { return InternalServerError(); } IdentityUser user = new IdentityUser { UserName = model.UserName }; user.Logins.Add(new IdentityUserLogin { LoginProvider = externalLogin.LoginProvider, ProviderKey = externalLogin.ProviderKey }); IdentityResult result = await UserManager.CreateAsync(user); IHttpActionResult errorResult = GetErrorResult(result); if (errorResult != null) { return errorResult; } return Ok(); } protected override void Dispose(bool disposing) { if (disposing) { UserManager.Dispose(); } base.Dispose(disposing); } #region Helpers private IAuthenticationManager Authentication { get { return Request.GetOwinContext().Authentication; } } private IHttpActionResult GetErrorResult(IdentityResult result) { if (result == null) { return InternalServerError(); } if (!result.Succeeded) { if (result.Errors != null) { foreach (string error in result.Errors) { ModelState.AddModelError("", error); } } if (ModelState.IsValid) { // No ModelState errors are available to send, so just return an empty BadRequest. return BadRequest(); } return BadRequest(ModelState); } return null; } private class ExternalLoginData { public string LoginProvider { get; set; } public string ProviderKey { get; set; } public string UserName { get; set; } public IList GetClaims() { IList claims = new List (); claims.Add(new Claim(ClaimTypes.NameIdentifier, ProviderKey, null, LoginProvider)); if (UserName != null) { claims.Add(new Claim(ClaimTypes.Name, UserName, null, LoginProvider)); } return claims; } public static ExternalLoginData FromIdentity(ClaimsIdentity identity) { if (identity == null) { return null; } Claim providerKeyClaim = identity.FindFirst(ClaimTypes.NameIdentifier); if (providerKeyClaim == null || String.IsNullOrEmpty(providerKeyClaim.Issuer) || String.IsNullOrEmpty(providerKeyClaim.Value)) { return null; } if (providerKeyClaim.Issuer == ClaimsIdentity.DefaultIssuer) { return null; } return new ExternalLoginData { LoginProvider = providerKeyClaim.Issuer, ProviderKey = providerKeyClaim.Value, UserName = identity.FindFirstValue(ClaimTypes.Name) }; } } private static class RandomOAuthStateGenerator { private static RandomNumberGenerator _random = new RNGCryptoServiceProvider(); public static string Generate(int strengthInBits) { const int bitsPerByte = 8; if (strengthInBits % bitsPerByte != 0) { throw new ArgumentException("strengthInBits must be evenly divisible by 8.", "strengthInBits"); } int strengthInBytes = strengthInBits / bitsPerByte; byte[] data = new byte[strengthInBytes]; _random.GetBytes(data); return HttpServerUtility.UrlTokenEncode(data); } } #endregion }
现在,我们可以看到,因为它正在使用RoutePrefix,他肯定是WebApi的2+版本.我的问题是代码无法编译.它指出:
找不到类型或命名空间名称'HostAuthenticationAttribute'(您是否缺少using指令或程序集引用?)
看看我干净的项目,我可以看到这个类驻留在System.Web.Http.Owin中.问题是,我的主项目中没有该引用,我不知道如何安装它.
我已经尝试安装所有其他不同版本的WebApi无济于事.
当然有人以前遇到过这个问题吗?
尝试将我的WebAPI项目升级到2.0版时,我遇到了同样的错误.安装nuget包Microsoft.AspNet.WebApi.Owin
解决了缺少的引用.
Install-Package Microsoft.AspNet.WebApi.Owin