我正在尝试使用本教程将OAuth 2.0添加到我的.NET Core 3.0 Web Api中。以下是 WebApiConfig 类的内容。
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute( // HERE IS THE ERROR
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// WebAPI when dealing with JSON & JavaScript!
// Setup json serialization to serialize classes to camel (std. Json format)
var formatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
formatter.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();
// Adding JSON type web api formatting.
config.Formatters.Clear();
config.Formatters.Add(formatter);
}
我猜它与依赖项有关,所以这里是 csproj:
<ItemGroup>
<PackageReference Include="EntityFramework" Version="6.4.0" />
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
<PackageReference Include="Microsoft.AspNet.WebApi.Core" Version="5.2.7" />
<PackageReference Include="Microsoft.AspNet.WebApi.Owin" Version="5.2.7" />
<PackageReference Include="Microsoft.AspNet.WebApi.WebHost" Version="5.2.7" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.0.0" />
<PackageReference Include="Microsoft.Owin.Cors" Version="4.1.0" />
<PackageReference Include="Microsoft.Owin.Security.OAuth" Version="4.1.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>
我看到过一个类似的问题,答案建议使用应用程序。UseMvc来映射路由,但他使用的是不同的.NET版本(2.0(。我也尝试使用应用程序。UseMvc,但它不做任何事情,因为我使用端点路由。
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentity<AppUser, AppRole>(options =>
{
options.User.RequireUniqueEmail = true;
}).AddEntityFrameworkStores<AppDbContext>();
services.AddControllers();
//+adding database and service/repository
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
所以我真的不知道该怎么办。我尝试关闭Visual Studio并删除项目中的每个obj,bin和vs文件夹(尽管这些声音很奇怪,但有些人建议它可以工作(,但没有成功。
有什么建议吗?
这也是我遇到的一个棘手的问题,但是当我搜索此错误消息的解决方案时,似乎没有人有一个优雅的解决方案......所以我自己找了一个。
这里有几个问题在起作用:
正如错误消息所指出的,方法MapHttpRoute已定义,但找不到
- 原因很简单:定义 HttpRouteCollectionExtensions 方法的文件不包括方法的实际主体!
- 当我们通过NugGet添加Microsoft.AspNet.WebApi包时,会安装此文件,并通过在文件顶部包含"using System.Web.Http;"来引用它 。
- 因此,对我有用的解决方案就是获取这些扩展的源代码并将它们直接包含在我的项目中
- 您可以在此处获取此源代码:
https://github.com/mono/aspnetwebstack/blob/master/src/System.Web.Http/HttpRouteCollectionExtensions.cs
- 顺便说一下,在GitHub上,您还可以找到其他类似定义但未找到的方法的源代码(即它们似乎由Microsoft提供(
因此,这解决了实现MapHttpRoute方法的问题...但这并不一定意味着您的 RESTFUL 服务电话会起作用!
这是因为这里实现的 HttpDelete 服务具有调用参数,这些参数必须通过 [路由] 和 [HttpDelete] 属性定义......这将我们引向第 2 步。
我们需要通过 [Route] 和 [HttpDelete] 属性显式声明调用参数
- 这实际上很简单,但是必不可少的
- 它将确保客户端在尝试访问 RESTful 服务时转到正确的位置
- 就我而言,我有两个用于删除服务的调用参数,它们都是字符串
- 因此,我调用配置中的路由模板。Routes.MapHttpRoute(name, routeTemplate, defaults( 看起来像这样:
routeTemplate = "api/{controller}/{userID}/{userName}";
- 然后在 C# 控制器(即发生被调用服务的文件(中,我修改了属性和服务方法,如下所示:
[Route("[controller]/{userID}/{userName}"(]
[HttpDelete("{userID}/{userName}"(]
public bool 删除(字符串用户 ID, 字符串用户名( =>这个。删除用户(用户ID,用户名(;
- 接下来,我定义实际使用参数的方法:
[路由("[控制器]"(]
public bool DeleteUser(string userIDParam, string userNameParam(
{
int? 用户 ID = 0; 字符串用户名 = ";
if (userIDParam != null( userID = Int16.Parse(userIDParam(;
if (用户名参数 != 空( 用户名 = 用户名参数;
返回删除指定用户(用户ID,用户名(;
}
- 在方法DeleteSpecified User(userID,userName(中,此处未显示,我在数据库中执行实际的删除操作
- 虽然就我而言我使用 ADO.Net,但它可以通过实体框架完成(但这超出了本讨论的范围(
- 当然,我可以只将 userID 作为整数发送,但此示例旨在说明使用两个调用参数执行某些操作
- 由于上面的原始问题只有一个调用参数(即int id(,因此这种情况更简单