Remove WebApiCompatShim and use the new ASP.Net Core Web API (#8)
* Remove WebApi shim * Replace httpget with httpget id * Fix API controller base class * Fix the installer after removing WebApiShim * Clean up readme.md
This commit is contained in:
Родитель
e086d562cc
Коммит
34175d3418
|
@ -134,8 +134,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{E05E
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.IIS.Administration.PsSetup", "scripts\Microsoft.IIS.Administration.PsSetup.csproj", "{C5FA05E9-0A3E-4C00-B261-CE35A568659D}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.IIS.Administration.WebApiCompatShim", "src\Microsoft.IIS.Administration.WebApiCompatShim\Microsoft.IIS.Administration.WebApiCompatShim.csproj", "{AA8D30E0-DCB6-449E-A19A-F68A3155F0F0}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Web.Administration.Refs", "src\Microsoft.Web.Administration.Refs\Microsoft.Web.Administration.Refs.csproj", "{2735D370-CA41-47D5-9CE3-3E05EC3E82C0}"
|
||||
EndProject
|
||||
Global
|
||||
|
@ -291,10 +289,6 @@ Global
|
|||
{C5FA05E9-0A3E-4C00-B261-CE35A568659D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C5FA05E9-0A3E-4C00-B261-CE35A568659D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C5FA05E9-0A3E-4C00-B261-CE35A568659D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AA8D30E0-DCB6-449E-A19A-F68A3155F0F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AA8D30E0-DCB6-449E-A19A-F68A3155F0F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AA8D30E0-DCB6-449E-A19A-F68A3155F0F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AA8D30E0-DCB6-449E-A19A-F68A3155F0F0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2735D370-CA41-47D5-9CE3-3E05EC3E82C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2735D370-CA41-47D5-9CE3-3E05EC3E82C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2735D370-CA41-47D5-9CE3-3E05EC3E82C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
@ -342,7 +336,6 @@ Global
|
|||
{6FDC4BDA-91D3-4269-B89B-043EDC7768F7} = {BC25CF2F-4139-4D3F-9DC5-279FD380D0F2}
|
||||
{F1AEBED1-CE86-48D2-8389-6559A088B6F8} = {5504DA5E-BCF3-409E-A285-E59EDBBBB8B8}
|
||||
{C5FA05E9-0A3E-4C00-B261-CE35A568659D} = {E05E8FAA-90EE-43C7-911F-4543FB491159}
|
||||
{AA8D30E0-DCB6-449E-A19A-F68A3155F0F0} = {BC25CF2F-4139-4D3F-9DC5-279FD380D0F2}
|
||||
{2735D370-CA41-47D5-9CE3-3E05EC3E82C0} = {BC25CF2F-4139-4D3F-9DC5-279FD380D0F2}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
|
|
91
README.md
91
README.md
|
@ -2,12 +2,47 @@
|
|||
Microsoft IIS Administration API
|
||||
--------------------------------
|
||||
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/l62ov4c6fbdi6vrq/branch/dev?svg=true)](https://ci.appveyor.com/project/jimmyca15/iis-administration-ed6b3/branch/dev)
|
||||
|
||||
To find the latest news for the IIS Administration api visit the blog at https://blogs.iis.net/adminapi.
|
||||
|
||||
Documentation is available at https://docs.microsoft.com/en-us/IIS-Administration
|
||||
|
||||
### Develop and Debug with Visual studio 2022: ###
|
||||
* Clone this project
|
||||
* Load the solution (Microsoft.IIS.Administration.sln) in Visual Studio
|
||||
* Try restoring all the NuGet packages
|
||||
* Open src\Microsoft.IIS.Administration\config\appsettings.json, modify the users section as below,
|
||||
```
|
||||
"users": {
|
||||
"administrators": [
|
||||
"mydomain\\myusername",
|
||||
"myusername@mycompany.com",
|
||||
"IIS Administration API Owners"
|
||||
],
|
||||
"owners": [
|
||||
"mydomain\\myusername",
|
||||
"myusername@mycompany.com",
|
||||
"IIS Administration API Owners"
|
||||
]
|
||||
},
|
||||
```
|
||||
* Run PowerShell as an Administrator
|
||||
* Run Configure-DevEnvironment.ps1 script in the scripts dir
|
||||
* From the visual studio run profile menu select option Microsoft.IIS.Administration and run the application.
|
||||
* If you are not able to browse the site or your getting generic browser error, most like SSL certificate is not configured for that. IIS express installs SSL certificates on port 44300-44399. Try changing the port to one of these in appsettings.json
|
||||
**ex: "urls":"https://*:44326"**
|
||||
|
||||
### Build the Installer: ###
|
||||
In the following code, replace the path to match your clone location. It first starts the developer command prompt for Visual Studio 2022, publishes the solution and finally, builds the installer at installer\IISAdministrationBundle\bin\x64\Release.
|
||||
```
|
||||
%comspec% /k "C:\Program Files\Microsoft Visual Studio\2022\Preview\Common7\Tools\VsDevCmd.bat"
|
||||
|
||||
cd /d C:\src\repos\IIS.Administration
|
||||
msbuild -restore Microsoft.IIS.Administration.sln /t:publish
|
||||
|
||||
build\nuget.exe restore installer\IISAdministrationSetup\packages.config -SolutionDirectory installer
|
||||
msbuild installer /p:configuration=release
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Installation and Known Issues: ###
|
||||
* Must first remove preview builds of .Net Core. The service does not work with preview builds of .Net Core.
|
||||
* Must remove previously installed versions of IIS Administration.
|
||||
|
@ -19,8 +54,6 @@ Documentation is available at https://docs.microsoft.com/en-us/IIS-Administratio
|
|||
* Microsoft.Web.Administration.dll version conflicts with .Net 6.0: Remove all code related to **_"ms.web.admin.refs"_** in the future when it is ported to .Net 6.0.
|
||||
* Supports 64 bit Windows Server 2008 R2 and above
|
||||
|
||||
The latest installer can be obtained from https://iis-manage.azurewebsites.net/get. The installer will automatically download and install all dependencies.
|
||||
|
||||
### Nano Server Installation: ###
|
||||
There is a blog post to get up and running on Nano Server located at https://blogs.iis.net/adminapi/microsoft-iis-administration-on-nano-server.
|
||||
|
||||
|
@ -76,52 +109,6 @@ JSON request
|
|||
* Open another instance of the project (also as Administrator since tests need to create new local users and enable some IIS features) and run the tests located in the 'test' folder
|
||||
* Tests can also be run with the CLI
|
||||
|
||||
### Publish and Install: ###
|
||||
Publishing and installing can be done through a PowerShell script. This requires the .NET Core SDK.
|
||||
|
||||
In the following code, replace the path to match your clone location. It first starts the developer command prompt for Visual Studio 2022, publishes the solution and finally, builds the installer at installer\IISAdministrationBundle\bin\x64\Release.
|
||||
```
|
||||
%comspec% /k "C:\Program Files\Microsoft Visual Studio\2022\Preview\Common7\Tools\VsDevCmd.bat"
|
||||
cd /d C:\src\repos\IIS.Administration
|
||||
msbuild -restore Microsoft.IIS.Administration.sln /t:publish
|
||||
|
||||
build\nuget.exe restore installer\IISAdministrationSetup\packages.config -SolutionDirectory installer
|
||||
msbuild installer /p:configuration=release
|
||||
```
|
||||
|
||||
### Develop and Debug in Visual studio 2022: ###
|
||||
* Clone this project
|
||||
* Load the project in visual studio
|
||||
* Try restoring all the NuGet packages
|
||||
* Open src\Microsoft.IIS.Administration\config\appsettings.json, modify the users section as below,
|
||||
```
|
||||
"users": {
|
||||
"administrators": [
|
||||
"mydomain\\myusername",
|
||||
"myusername@mycompany.com",
|
||||
"IIS Administration API Owners"
|
||||
],
|
||||
"owners": [
|
||||
"mydomain\\myusername",
|
||||
"myusername@mycompany.com",
|
||||
"IIS Administration API Owners"
|
||||
]
|
||||
},
|
||||
```
|
||||
* Run PowerShell as an Administrator
|
||||
* Run Configure-DevEnvironment.ps1 script in the scripts dir
|
||||
* From the visual studio run profile menu select option Microsoft.IIS.Administration and run the application.
|
||||
* If you are not able to browse the site or your getting generic browser error, most like SSL certificate is not configured for that. IIS express installs SSL certificates on port 44300-44399. Try changing the port to one of these in appsettings.json
|
||||
**ex: "urls":"https://*:44326"**
|
||||
|
||||
### Using the new API ###
|
||||
1. Navigate to https://manage.iis.net
|
||||
2. Click 'Get Access Token'
|
||||
3. Generate an access token and copy it to the clipboard
|
||||
4. Exit the access tokens window and return to the connection screen
|
||||
5. Paste the access token into the Access Token field of the connection screen
|
||||
6. Click 'Connect'
|
||||
|
||||
## Examples ##
|
||||
|
||||
### C# ###
|
||||
|
|
|
@ -77,9 +77,6 @@
|
|||
<Component Id="C_Microsoft.IIS.Administration.Files.Core.dll" Guid="e6dd3e96-b6bf-428d-8145-f613433da408" Win64="$(var.IsWin64)">
|
||||
<File Id="Microsoft.IIS.Administration.Files.Core.dll" Source="$(var.APIDir)\plugins\Microsoft.IIS.Administration.Files.Core.dll" />
|
||||
</Component>
|
||||
<Component Id="C_Microsoft.IIS.Administration.WebApiCompatShim.dll" Guid="181d8423-3a90-4a7f-9178-2b210dd2e79e" Win64="$(var.IsWin64)">
|
||||
<File Id="Microsoft.IIS.Administration.WebApiCompatShim.dll" Source="$(var.APIDir)\plugins\Microsoft.IIS.Administration.WebApiCompatShim.dll" />
|
||||
</Component>
|
||||
<Component Id="C_Newtonsoft.Json.Bson.dll" Guid="d17aec10-b477-4e35-9534-71471db52908" Win64="$(var.IsWin64)">
|
||||
<File Id="Newtonsoft.Json.Bson.dll" Source="$(var.APIDir)\Newtonsoft.Json.Bson.dll" />
|
||||
</Component>
|
||||
|
@ -101,9 +98,6 @@
|
|||
<Component Id="C_System.IdentityModel.Tokens.Jwt.dll" Guid="36e521bf-65d7-4e61-a7bf-33d8e85211d3" Win64="$(var.IsWin64)">
|
||||
<File Id="System.IdentityModel.Tokens.Jwt.dll" Source="$(var.APIDir)\System.IdentityModel.Tokens.Jwt.dll" />
|
||||
</Component>
|
||||
<Component Id="C_System.Net.Http.Formatting.dll" Guid="68b6cece-1ea7-4556-915b-8b4b6d4396f8" Win64="$(var.IsWin64)">
|
||||
<File Id="System.Net.Http.Formatting.dll" Source="$(var.APIDir)\System.Net.Http.Formatting.dll" />
|
||||
</Component>
|
||||
<Component Id="C_System.ServiceProcess.ServiceController.dll" Guid="f693f958-dff6-4fd5-a236-47f88d735dee" Win64="$(var.IsWin64)">
|
||||
<File Id="System.ServiceProcess.ServiceController.dll" Source="$(var.APIDir)\System.ServiceProcess.ServiceController.dll" />
|
||||
</Component>
|
||||
|
|
|
@ -2,19 +2,20 @@
|
|||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
|
||||
namespace Microsoft.IIS.Administration.AccessManagement {
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Http;
|
||||
namespace Microsoft.IIS.Administration.AccessManagement
|
||||
{
|
||||
using AspNetCore.Antiforgery;
|
||||
using AspNetCore.Authorization;
|
||||
using AspNetCore.Cors;
|
||||
using AspNetCore.Mvc;
|
||||
using Core;
|
||||
using Core.Http;
|
||||
using Core.Security;
|
||||
using Core.Utils;
|
||||
using Extensions.Options;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
/// <summary>
|
||||
|
@ -24,7 +25,8 @@ namespace Microsoft.IIS.Administration.AccessManagement {
|
|||
// AntiForgery MUST be applied
|
||||
/// </summary>
|
||||
[Authorize(Policy = "ApiKeys")]
|
||||
[DisableCors]
|
||||
[DisableCors]
|
||||
[Route("security/access-tokens")]
|
||||
public class AccessTokensController : ApiController {
|
||||
IApiKeyProvider _keyProvider;
|
||||
|
||||
|
@ -46,7 +48,7 @@ namespace Microsoft.IIS.Administration.AccessManagement {
|
|||
Context.Response.StatusCode = (int)HttpStatusCode.NoContent;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.AccessTokenName)]
|
||||
public object Get(string id) {
|
||||
SetAntiForgeryTokens();
|
||||
|
|
|
@ -27,7 +27,8 @@ namespace Microsoft.IIS.Administration.AccessManagement {
|
|||
/// </summary>
|
||||
[Authorize(Policy = "ApiKeys")]
|
||||
[DisableCors]
|
||||
public class ApiKeysController : ApiEdgeController {
|
||||
[Route("security/api-keys")]
|
||||
public class ApiKeysController : ApiController {
|
||||
IApiKeyProvider _keyProvider;
|
||||
|
||||
public ApiKeysController(IApiKeyProvider keyProvider) {
|
||||
|
@ -49,7 +50,7 @@ namespace Microsoft.IIS.Administration.AccessManagement {
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.ApiKeyName)]
|
||||
public object Get(string id) {
|
||||
ApiKey key = _keyProvider.GetKey(id);
|
||||
|
@ -94,7 +95,7 @@ namespace Microsoft.IIS.Administration.AccessManagement {
|
|||
|
||||
|
||||
[ValidateAntiForgeryToken]
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[ResourceInfo(Name = Defines.ApiKeyName)]
|
||||
public async Task<object> Patch(string id, [FromBody] dynamic model) {
|
||||
model = DynamicHelper.ToJObject(model);
|
||||
|
@ -113,7 +114,7 @@ namespace Microsoft.IIS.Administration.AccessManagement {
|
|||
|
||||
|
||||
[ValidateAntiForgeryToken]
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
public async Task Delete(string id) {
|
||||
ApiKey key = _keyProvider.GetKey(id);
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace Microsoft.IIS.Administration.AccessManagement {
|
|||
using Core.Security;
|
||||
|
||||
|
||||
[Route("api/access-token")]
|
||||
public class MyTokenController : ApiBaseController {
|
||||
IApiKeyProvider _keyProvider;
|
||||
|
||||
|
@ -46,7 +47,7 @@ namespace Microsoft.IIS.Administration.AccessManagement {
|
|||
// Renew the key
|
||||
string token = await _keyProvider.RenewToken(key);
|
||||
|
||||
return Created(Request.RequestUri.PathAndQuery,
|
||||
return Created(RequestUri.PathAndQuery,
|
||||
AccessTokenHelper.ToJsonModel(new ApiToken() { Token=token, Key=key }));
|
||||
}
|
||||
|
||||
|
@ -64,10 +65,10 @@ namespace Microsoft.IIS.Administration.AccessManagement {
|
|||
return tokenClaim == null ? null : _keyProvider.FindKey(tokenClaim.Value);
|
||||
}
|
||||
|
||||
protected override string GetId() {
|
||||
ApiKey key = GetCurrentApiKey();
|
||||
//protected override string GetId() {
|
||||
// ApiKey key = GetCurrentApiKey();
|
||||
|
||||
return key == null ? throw new NotFoundException("Access Token") : key.Id;
|
||||
}
|
||||
// return key == null ? throw new NotFoundException("Access Token") : key.Id;
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Microsoft.IIS.Administration.Certificates
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
[Route("api/certificates/stores")]
|
||||
public class CertificateStoresController : ApiBaseController
|
||||
{
|
||||
private ICertificateStoreProvider _provider;
|
||||
|
@ -30,7 +31,7 @@ namespace Microsoft.IIS.Administration.Certificates
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.StoresName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace Microsoft.IIS.Administration.Certificates
|
|||
using Core;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
[Route("api/certificates")]
|
||||
public class CertificatesController : ApiBaseController
|
||||
{
|
||||
private const string _units = "certificates";
|
||||
|
@ -86,7 +87,7 @@ namespace Microsoft.IIS.Administration.Certificates
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.CertificateName)]
|
||||
public async Task<object> Get(string id)
|
||||
{
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace Microsoft.IIS.Administration.Core.Http {
|
|||
|
||||
|
||||
[Authorize(Policy ="Api")]
|
||||
public abstract class ApiBaseController : ApiEdgeController {
|
||||
public abstract class ApiBaseController : ApiController {
|
||||
public virtual LocationChangedResult LocationChanged(string location, object content) {
|
||||
return new LocationChangedResult(location, content);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.IIS.Administration.Core.Http
|
||||
{
|
||||
// Derived classes must provide Route attribute such as [Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public abstract class ApiController : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Microsoft.AspNetCore.Mvc.ActionContext"/>.
|
||||
/// </summary>
|
||||
public ActionContext ActionContext => ControllerContext;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the http context.
|
||||
/// </summary>
|
||||
public HttpContext Context
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.HttpContext;
|
||||
}
|
||||
}
|
||||
|
||||
public Uri RequestUri
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Uri(Request.GetEncodedUrl());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,13 +4,15 @@
|
|||
|
||||
namespace Microsoft.IIS.Administration.Core.Http {
|
||||
using System;
|
||||
using System.Web.Http;
|
||||
using AspNetCore.Authorization;
|
||||
using AspNetCore.Http;
|
||||
using AspNetCore.Mvc;
|
||||
using Utils;
|
||||
|
||||
|
||||
// This class is not being used since MapRoute does not work when ApiController attribute is used.
|
||||
// Keep the class here for possible future use.
|
||||
// It is called through MapEdgeWebApiRoutes in AdminHost.cs
|
||||
[Authorize]
|
||||
public abstract class ApiEdgeController : ApiController {
|
||||
[HttpGet]
|
||||
|
@ -46,7 +48,7 @@ namespace Microsoft.IIS.Administration.Core.Http {
|
|||
|
||||
// Make absolute Uri
|
||||
if (!uri.IsAbsoluteUri) {
|
||||
var baseUrl = new Uri(Request.RequestUri.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped), UriKind.Absolute);
|
||||
var baseUrl = new Uri(RequestUri.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped), UriKind.Absolute);
|
||||
uri = new Uri(baseUrl, redirectUrl);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
|
||||
|
||||
namespace Microsoft.IIS.Administration.Core.Http {
|
||||
using AspNetCore.Routing;
|
||||
using AspNetCore.Builder;
|
||||
using AspNetCore.Routing;
|
||||
using AspNetCore.Routing.Constraints;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Utils;
|
||||
|
||||
public static class IRouteBuilderExtensions {
|
||||
|
@ -25,5 +27,73 @@ namespace Microsoft.IIS.Administration.Core.Http {
|
|||
// Add Route
|
||||
return builder.MapWebApiRoute(resourceId.ToString(), template, (object) def);
|
||||
}
|
||||
|
||||
public static IRouteBuilder MapWebApiRoute(
|
||||
this IRouteBuilder routeCollectionBuilder,
|
||||
string name,
|
||||
string template)
|
||||
{
|
||||
return MapWebApiRoute(routeCollectionBuilder, name, template, defaults: null);
|
||||
}
|
||||
|
||||
public static IRouteBuilder MapWebApiRoute(
|
||||
this IRouteBuilder routeCollectionBuilder,
|
||||
string name,
|
||||
string template,
|
||||
object defaults)
|
||||
{
|
||||
return MapWebApiRoute(routeCollectionBuilder, name, template, defaults, constraints: null);
|
||||
}
|
||||
|
||||
public static IRouteBuilder MapWebApiRoute(
|
||||
this IRouteBuilder routeCollectionBuilder,
|
||||
string name,
|
||||
string template,
|
||||
object defaults,
|
||||
object constraints)
|
||||
{
|
||||
return MapWebApiRoute(routeCollectionBuilder, name, template, defaults, constraints, dataTokens: null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When we use ApiController attribute for Controller classes, MapRoute() does not create a working route
|
||||
/// Keep this function here for possible future use.
|
||||
/// </summary>
|
||||
/// <param name="routeCollectionBuilder"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="template"></param>
|
||||
/// <param name="defaults"></param>
|
||||
/// <param name="constraints"></param>
|
||||
/// <param name="dataTokens"></param>
|
||||
/// <returns></returns>
|
||||
public static IRouteBuilder MapWebApiRoute(
|
||||
this IRouteBuilder routeCollectionBuilder,
|
||||
string name,
|
||||
string template,
|
||||
object defaults,
|
||||
object constraints,
|
||||
object dataTokens)
|
||||
{
|
||||
var mutableDefaults = ObjectToDictionary(defaults);
|
||||
mutableDefaults.Add("area", Globals.API_PATH); // default area name is "api"
|
||||
|
||||
var mutableConstraints = ObjectToDictionary(constraints);
|
||||
mutableConstraints.Add("area", new RequiredRouteConstraint());
|
||||
|
||||
return routeCollectionBuilder.MapRoute(name, template, mutableDefaults, mutableConstraints, dataTokens);
|
||||
}
|
||||
|
||||
private static IDictionary<string, object> ObjectToDictionary(object value)
|
||||
{
|
||||
var dictionary = value as IDictionary<string, object>;
|
||||
if (dictionary != null)
|
||||
{
|
||||
return new RouteValueDictionary(dictionary);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new RouteValueDictionary(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,6 +11,10 @@
|
|||
<PackageId>Microsoft.IIS.Administration.Core</PackageId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Http\ApiEdgeController.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
<PackageReference Include="MicroBuild.Core" Version="$(MicroBuildCoreVersion)">
|
||||
|
@ -18,13 +22,9 @@
|
|||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="3.1.0" />
|
||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
<PackageReference Include="Serilog" Version="2.11.0" />
|
||||
<PackageReference Include="Serilog.Sinks.RollingFile" Version="3.3.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Microsoft.IIS.Administration.WebApiCompatShim\Microsoft.IIS.Administration.WebApiCompatShim.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
using AspNetCore.Mvc;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
[Route("api/files/content")]
|
||||
public class ContentController : ApiBaseController
|
||||
{
|
||||
private IFileProvider _fileProvider;
|
||||
|
@ -19,7 +20,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
_redirectService = redirectService;
|
||||
}
|
||||
|
||||
[HttpHead]
|
||||
[HttpHead("{id}")]
|
||||
public IActionResult Head(string id)
|
||||
{
|
||||
FileId fileId = FileId.FromUuid(id);
|
||||
|
@ -36,7 +37,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
return new EmptyResult();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
public async Task<IActionResult> Get(string id)
|
||||
{
|
||||
//
|
||||
|
@ -62,7 +63,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
return new EmptyResult();
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
[HttpPut("{id}")]
|
||||
public async Task<IActionResult> Put(string id)
|
||||
{
|
||||
FileId fileId = FileId.FromUuid(id);
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
[Route("api/files/copy")]
|
||||
public class CopyController : ApiBaseController
|
||||
{
|
||||
private MoveHelper _helper;
|
||||
|
@ -70,7 +71,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
return _helper.ToJsonModel(copy);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
public object Get(string id)
|
||||
{
|
||||
MoveOperation copy = null;
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
[Route("downloads")]
|
||||
[AllowAnonymous]
|
||||
public class DownloadsController : ApiBaseController
|
||||
{
|
||||
|
@ -28,7 +28,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
_redirectService = redirectService;
|
||||
}
|
||||
|
||||
[HttpHead]
|
||||
[HttpHead("{id}")]
|
||||
public IActionResult Head(string id)
|
||||
{
|
||||
var dl = _downloadService.Get(id);
|
||||
|
@ -47,7 +47,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
return new EmptyResult();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
public async Task<IActionResult> Get(string id)
|
||||
{
|
||||
//
|
||||
|
@ -80,7 +80,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
return new EmptyResult();
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
public IActionResult Delete(string id)
|
||||
{
|
||||
_downloadService.Remove(id);
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
using System.Net;
|
||||
using System.Reflection;
|
||||
|
||||
[Route("api/files/downloads")]
|
||||
public class FileDownloadsController : ApiBaseController
|
||||
{
|
||||
private const int DEFAULT_DOWNLOAD_TIMEOUT = 5000; // milliseconds
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
using System.Linq;
|
||||
using System.Net;
|
||||
|
||||
[Route("api/files")]
|
||||
public class FilesController : ApiBaseController
|
||||
{
|
||||
private const string _units = "files";
|
||||
|
@ -114,7 +115,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.FileName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
@ -195,7 +196,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
return Created(FilesHelper.GetLocation(file.id), _helper.ToJsonModel(info));
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.FileName)]
|
||||
public object Patch([FromBody] dynamic model, string id)
|
||||
|
@ -231,7 +232,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
return result;
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public IActionResult Delete(string id)
|
||||
{
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
using System.Threading.Tasks;
|
||||
|
||||
[Authorize(Policy = "System")]
|
||||
[Route("api/files/locations")]
|
||||
public class LocationsController : ApiBaseController
|
||||
{
|
||||
LocationsHelper _helper;
|
||||
|
@ -33,7 +34,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.LocationsName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
@ -48,7 +49,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
return _helper.ToJsonModel(location);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[ResourceInfo(Name = Defines.LocationsName)]
|
||||
[Audit(AuditAttribute.ALL)]
|
||||
public async Task<object> Patch([FromBody] dynamic model, string id)
|
||||
|
@ -89,7 +90,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
return Created(_helper.GetLocationPath(locModel.id), locModel);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit(AuditAttribute.ALL)]
|
||||
public async Task Delete(string id)
|
||||
{
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
[Route("api/files/move")]
|
||||
public class MoveController : ApiBaseController
|
||||
{
|
||||
private MoveHelper _helper;
|
||||
|
@ -70,7 +71,7 @@ namespace Microsoft.IIS.Administration.Files
|
|||
return _helper.ToJsonModel(move);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
public object Get(string id)
|
||||
{
|
||||
MoveOperation move = null;
|
||||
|
|
|
@ -1,580 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using Microsoft.IIS.Administration.WebApiCompatShim;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace System.Web.Http
|
||||
{
|
||||
[UseWebApiRoutes]
|
||||
[UseWebApiActionConventions]
|
||||
[UseWebApiParameterConventions]
|
||||
[UseWebApiOverloading]
|
||||
[Controller]
|
||||
public abstract class ApiController : IDisposable
|
||||
{
|
||||
private ControllerContext _controllerContext;
|
||||
private HttpRequestMessage _request;
|
||||
private IModelMetadataProvider _metadataProvider;
|
||||
private IObjectModelValidator _objectValidator;
|
||||
private IUrlHelper _urlHelper;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Microsoft.AspNetCore.Mvc.ActionContext"/>.
|
||||
/// </summary>
|
||||
public ActionContext ActionContext => ControllerContext;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="ControllerContext"/>.
|
||||
/// </summary>
|
||||
/// <remarks>The setter is intended for unit testing purposes only.</remarks>
|
||||
[ControllerContext]
|
||||
public ControllerContext ControllerContext
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_controllerContext == null)
|
||||
{
|
||||
_controllerContext = new ControllerContext();
|
||||
}
|
||||
|
||||
return _controllerContext;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
_controllerContext = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the http context.
|
||||
/// </summary>
|
||||
public HttpContext Context
|
||||
{
|
||||
get
|
||||
{
|
||||
return ControllerContext.HttpContext;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IModelMetadataProvider"/>.
|
||||
/// </summary>
|
||||
/// <remarks>The setter is intended for unit testing purposes only.</remarks>
|
||||
public IModelMetadataProvider MetadataProvider
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_metadataProvider == null)
|
||||
{
|
||||
_metadataProvider = Context?.RequestServices.GetRequiredService<IModelMetadataProvider>();
|
||||
}
|
||||
|
||||
return _metadataProvider;
|
||||
}
|
||||
set
|
||||
{
|
||||
_metadataProvider = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="IObjectModelValidator"/>.
|
||||
/// </summary>
|
||||
public IObjectModelValidator ObjectValidator
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_objectValidator == null)
|
||||
{
|
||||
_objectValidator = Context?.RequestServices.GetRequiredService<IObjectModelValidator>();
|
||||
}
|
||||
|
||||
return _objectValidator;
|
||||
}
|
||||
set
|
||||
{
|
||||
_objectValidator = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets model state after the model binding process. This ModelState will be empty before model binding
|
||||
/// happens.
|
||||
/// </summary>
|
||||
public ModelStateDictionary ModelState
|
||||
{
|
||||
get
|
||||
{
|
||||
return ControllerContext.ModelState;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the HTTP request message.
|
||||
/// </summary>
|
||||
/// <remarks>The setter is intended for unit testing purposes only.</remarks>
|
||||
public HttpRequestMessage Request
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_request == null && ActionContext != null)
|
||||
{
|
||||
_request = ControllerContext.HttpContext.GetHttpRequestMessage();
|
||||
}
|
||||
|
||||
return _request;
|
||||
}
|
||||
set
|
||||
{
|
||||
_request = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a factory used to generate URLs to other APIs.
|
||||
/// </summary>
|
||||
/// <remarks>The setter is intended for unit testing purposes only.</remarks>
|
||||
public IUrlHelper Url
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_urlHelper == null)
|
||||
{
|
||||
var factory = Context?.RequestServices.GetRequiredService<IUrlHelperFactory>();
|
||||
_urlHelper = factory?.GetUrlHelper(ActionContext);
|
||||
}
|
||||
|
||||
return _urlHelper;
|
||||
}
|
||||
set
|
||||
{
|
||||
_urlHelper = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current principal associated with this request.
|
||||
/// </summary>
|
||||
public IPrincipal User
|
||||
{
|
||||
get
|
||||
{
|
||||
return Context?.User;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="BadRequestResult"/> (400 Bad Request).
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="BadRequestResult"/>.</returns>
|
||||
[NonAction]
|
||||
public virtual BadRequestResult BadRequest()
|
||||
{
|
||||
return new BadRequestResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="BadRequestErrorMessageResult"/> (400 Bad Request) with the specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The user-visible error message.</param>
|
||||
/// <returns>A <see cref="BadRequestErrorMessageResult"/> with the specified error message.</returns>
|
||||
[NonAction]
|
||||
public virtual BadRequestErrorMessageResult BadRequest(string message)
|
||||
{
|
||||
if (message == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(message));
|
||||
}
|
||||
|
||||
return new BadRequestErrorMessageResult(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="InvalidModelStateResult"/> (400 Bad Request) with the specified model state.
|
||||
/// </summary>
|
||||
/// <param name="modelState">The model state to include in the error.</param>
|
||||
/// <returns>An <see cref="InvalidModelStateResult"/> with the specified model state.</returns>
|
||||
[NonAction]
|
||||
public virtual InvalidModelStateResult BadRequest(ModelStateDictionary modelState)
|
||||
{
|
||||
if (modelState == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(modelState));
|
||||
}
|
||||
|
||||
return new InvalidModelStateResult(modelState, includeErrorDetail: false);
|
||||
}
|
||||
|
||||
/// <summary>Creates a <see cref="ConflictResult"/> (409 Conflict).</summary>
|
||||
/// <returns>A <see cref="ConflictResult"/>.</returns>
|
||||
[NonAction]
|
||||
public virtual ConflictResult Conflict()
|
||||
{
|
||||
return new ConflictResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="NegotiatedContentResult{T}"/> with the specified values.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of content in the entity body.</typeparam>
|
||||
/// <param name="statusCode">The HTTP status code for the response message.</param>
|
||||
/// <param name="value">The content value to negotiate and format in the entity body.</param>
|
||||
/// <returns>A <see cref="NegotiatedContentResult{T}"/> with the specified values.</returns>
|
||||
[NonAction]
|
||||
public virtual NegotiatedContentResult<T> Content<T>(HttpStatusCode statusCode, T value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
return new NegotiatedContentResult<T>(statusCode, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="CreatedResult"/> (201 Created) with the specified values.
|
||||
/// </summary>
|
||||
/// <param name="location">
|
||||
/// The location at which the content has been created. Must be a relative or absolute URL.
|
||||
/// </param>
|
||||
/// <param name="content">The content value to format in the entity body.</param>
|
||||
/// <returns>A <see cref="CreatedResult"/> with the specified values.</returns>
|
||||
[NonAction]
|
||||
public virtual CreatedResult Created(string location, object content)
|
||||
{
|
||||
if (location == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(location));
|
||||
}
|
||||
|
||||
return new CreatedResult(location, content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="CreatedResult"/> (201 Created) with the specified values.
|
||||
/// </summary>
|
||||
/// <param name="uri">The location at which the content has been created.</param>
|
||||
/// <param name="content">The content value to format in the entity body.</param>
|
||||
/// <returns>A <see cref="CreatedResult"/> with the specified values.</returns>
|
||||
[NonAction]
|
||||
public virtual CreatedResult Created(Uri uri, object content)
|
||||
{
|
||||
if (uri == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(uri));
|
||||
}
|
||||
|
||||
string location;
|
||||
if (uri.IsAbsoluteUri)
|
||||
{
|
||||
location = uri.AbsoluteUri;
|
||||
}
|
||||
else
|
||||
{
|
||||
location = uri.GetComponents(UriComponents.SerializationInfoString, UriFormat.UriEscaped);
|
||||
}
|
||||
return Created(location, content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="CreatedAtRouteResult"/> (201 Created) with the specified values.
|
||||
/// </summary>
|
||||
/// <param name="routeName">The name of the route to use for generating the URL.</param>
|
||||
/// <param name="routeValues">The route data to use for generating the URL.</param>
|
||||
/// <param name="content">The content value to format in the entity body.</param>
|
||||
/// <returns>A <see cref="CreatedAtRouteResult"/> with the specified values.</returns>
|
||||
[NonAction]
|
||||
public virtual CreatedAtRouteResult CreatedAtRoute(
|
||||
string routeName,
|
||||
object routeValues,
|
||||
object content)
|
||||
{
|
||||
if (routeName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(routeName));
|
||||
}
|
||||
|
||||
return new CreatedAtRouteResult(routeName, routeValues, content);
|
||||
}
|
||||
|
||||
/// <summary
|
||||
/// >Creates an <see cref="InternalServerErrorResult"/> (500 Internal Server Error).
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="InternalServerErrorResult"/>.</returns>
|
||||
[NonAction]
|
||||
public virtual InternalServerErrorResult InternalServerError()
|
||||
{
|
||||
return new InternalServerErrorResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="ExceptionResult"/> (500 Internal Server Error) with the specified exception.
|
||||
/// </summary>
|
||||
/// <param name="exception">The exception to include in the error.</param>
|
||||
/// <returns>An <see cref="ExceptionResult"/> with the specified exception.</returns>
|
||||
[NonAction]
|
||||
public virtual ExceptionResult InternalServerError(Exception exception)
|
||||
{
|
||||
if (exception == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(exception));
|
||||
}
|
||||
|
||||
return new ExceptionResult(exception, includeErrorDetail: false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="JsonResult"/> (200 OK) with the specified value.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of content in the entity body.</typeparam>
|
||||
/// <param name="content">The content value to serialize in the entity body.</param>
|
||||
/// <returns>A <see cref="JsonResult"/> with the specified value.</returns>
|
||||
[NonAction]
|
||||
public virtual JsonResult Json<T>(T content)
|
||||
{
|
||||
if (content == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(content));
|
||||
}
|
||||
|
||||
return new JsonResult(content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="JsonResult"/> (200 OK) with the specified values.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of content in the entity body.</typeparam>
|
||||
/// <param name="content">The content value to serialize in the entity body.</param>
|
||||
/// <param name="serializerSettings">The serializer settings.</param>
|
||||
/// <returns>A <see cref="JsonResult"/> with the specified values.</returns>
|
||||
[NonAction]
|
||||
public virtual JsonResult Json<T>(T content, JsonSerializerSettings serializerSettings)
|
||||
{
|
||||
if (content == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(content));
|
||||
}
|
||||
|
||||
if (serializerSettings == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(serializerSettings));
|
||||
}
|
||||
|
||||
return new JsonResult(content, serializerSettings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="JsonResult"/> (200 OK) with the specified values.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of content in the entity body.</typeparam>
|
||||
/// <param name="content">The content value to serialize in the entity body.</param>
|
||||
/// <param name="serializerSettings">The serializer settings.</param>
|
||||
/// <param name="encoding">The content encoding.</param>
|
||||
/// <returns>A <see cref="JsonResult"/> with the specified values.</returns>
|
||||
[NonAction]
|
||||
public virtual JsonResult Json<T>(
|
||||
T content,
|
||||
JsonSerializerSettings serializerSettings,
|
||||
Encoding encoding)
|
||||
{
|
||||
if (content == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(content));
|
||||
}
|
||||
|
||||
if (serializerSettings == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(serializerSettings));
|
||||
}
|
||||
|
||||
if (encoding == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(encoding));
|
||||
}
|
||||
|
||||
var result = new JsonResult(content, serializerSettings);
|
||||
result.ContentType = $"application/json; charset={encoding.WebName}";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="NotFoundResult"/> (404 Not Found).
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="NotFoundResult"/>.</returns>
|
||||
[NonAction]
|
||||
public virtual NotFoundResult NotFound()
|
||||
{
|
||||
return new NotFoundResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="OkResult"/> (200 OK).
|
||||
/// </summary>
|
||||
/// <returns>An <see cref="OkResult"/>.</returns>
|
||||
[NonAction]
|
||||
public virtual OkResult Ok()
|
||||
{
|
||||
return new OkResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="OkObjectResult"/> (200 OK) with the specified values.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of content in the entity body.</typeparam>
|
||||
/// <param name="content">The content value to negotiate and format in the entity body.</param>
|
||||
/// <returns>An <see cref="OkObjectResult"/> with the specified values.</returns>
|
||||
[NonAction]
|
||||
public virtual OkObjectResult Ok<T>(T content)
|
||||
{
|
||||
return new OkObjectResult(content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="RedirectResult"/> (302 Found) with the specified value.
|
||||
/// </summary>
|
||||
/// <param name="location">The location to which to redirect.</param>
|
||||
/// <returns>A <see cref="RedirectResult"/> with the specified value.</returns>
|
||||
[NonAction]
|
||||
public virtual RedirectResult Redirect(string location)
|
||||
{
|
||||
if (location == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(location));
|
||||
}
|
||||
|
||||
// This is how redirect was implemented in legacy webapi - string URIs are assumed to be absolute.
|
||||
return Redirect(new Uri(location));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="RedirectResult"/> (302 Found) with the specified value.
|
||||
/// </summary>
|
||||
/// <param name="location">The location to which to redirect.</param>
|
||||
/// <returns>A <see cref="RedirectResult"/> with the specified value.</returns>
|
||||
[NonAction]
|
||||
public virtual RedirectResult Redirect(Uri location)
|
||||
{
|
||||
if (location == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(location));
|
||||
}
|
||||
|
||||
string uri;
|
||||
if (location.IsAbsoluteUri)
|
||||
{
|
||||
uri = location.AbsoluteUri;
|
||||
}
|
||||
else
|
||||
{
|
||||
uri = location.GetComponents(UriComponents.SerializationInfoString, UriFormat.UriEscaped);
|
||||
}
|
||||
|
||||
return new RedirectResult(uri);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="RedirectToRouteResult"/> (302 Found) with the specified values.
|
||||
/// </summary>
|
||||
/// <param name="routeName">The name of the route to use for generating the URL.</param>
|
||||
/// <param name="routeValues">The route data to use for generating the URL.</param>
|
||||
/// <returns>A <see cref="RedirectToRouteResult"/> with the specified values.</returns>
|
||||
[NonAction]
|
||||
public virtual RedirectToRouteResult RedirectToRoute(string routeName, object routeValues)
|
||||
{
|
||||
if (routeName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(routeName));
|
||||
}
|
||||
|
||||
if (routeValues == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(routeValues));
|
||||
}
|
||||
|
||||
return new RedirectToRouteResult(routeName, routeValues)
|
||||
{
|
||||
UrlHelper = Url,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="ResponseMessageResult"/> with the specified response.
|
||||
/// </summary>
|
||||
/// <param name="response">The HTTP response message.</param>
|
||||
/// <returns>A <see cref="ResponseMessageResult"/> for the specified response.</returns>
|
||||
[NonAction]
|
||||
public virtual ResponseMessageResult ResponseMessage(HttpResponseMessage response)
|
||||
{
|
||||
if (response == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(response));
|
||||
}
|
||||
|
||||
return new ResponseMessageResult(response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="StatusCodeResult"/> with the specified status code.
|
||||
/// </summary>
|
||||
/// <param name="status">The HTTP status code for the response message</param>
|
||||
/// <returns>A <see cref="StatusCodeResult"/> with the specified status code.</returns>
|
||||
[NonAction]
|
||||
public virtual StatusCodeResult StatusCode(HttpStatusCode status)
|
||||
{
|
||||
return new StatusCodeResult((int)status);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose() => Dispose(disposing: true);
|
||||
|
||||
/// <summary>
|
||||
/// Validates the given entity and adds the validation errors to the <see cref="ApiController.ModelState"/>
|
||||
/// under an empty prefix.
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity">The type of the entity to be validated.</typeparam>
|
||||
/// <param name="entity">The entity being validated.</param>
|
||||
public void Validate<TEntity>(TEntity entity)
|
||||
{
|
||||
Validate(entity, keyPrefix: string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the given entity and adds the validation errors to the <see cref="ApiController.ModelState"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity">The type of the entity to be validated.</typeparam>
|
||||
/// <param name="entity">The entity being validated.</param>
|
||||
/// <param name="keyPrefix">
|
||||
/// The key prefix under which the model state errors would be added in the
|
||||
/// <see cref="ApiController.ModelState"/>.
|
||||
/// </param>
|
||||
public void Validate<TEntity>(TEntity entity, string keyPrefix)
|
||||
{
|
||||
ObjectValidator.Validate(
|
||||
ControllerContext,
|
||||
validationState: null,
|
||||
prefix: keyPrefix,
|
||||
model: entity);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace System.Web.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// An action result that returns a <see cref="StatusCodes.Status400BadRequest"/> response and performs
|
||||
/// content negotiation on an <see cref="HttpError"/> with a <see cref="HttpError.Message"/>.
|
||||
/// </summary>
|
||||
public class BadRequestErrorMessageResult : ObjectResult
|
||||
{
|
||||
/// <summary>Initializes a new instance of the <see cref="BadRequestErrorMessageResult"/> class.</summary>
|
||||
/// <param name="message">The user-visible error message.</param>
|
||||
public BadRequestErrorMessageResult(string message)
|
||||
: base(new HttpError(message))
|
||||
{
|
||||
if (message == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(message));
|
||||
}
|
||||
|
||||
Message = message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the error message.
|
||||
/// </summary>
|
||||
public string Message { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task ExecuteResultAsync(ActionContext context)
|
||||
{
|
||||
context.HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||
return base.ExecuteResultAsync(context);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace System.Web.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// An action result that returns an empty <see cref="StatusCodes.Status409Conflict"/> response.
|
||||
/// </summary>
|
||||
public class ConflictResult : StatusCodeResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConflictResult"/> class.
|
||||
/// </summary>
|
||||
public ConflictResult()
|
||||
: base(StatusCodes.Status409Conflict)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates actions without attribute routes in a controller use ASP.NET Web API routing conventions.
|
||||
/// </summary>
|
||||
public interface IUseWebApiActionConventions
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates actions in a controller should be selected only if all non-optional parameters are satisfied. Applies
|
||||
/// the <see cref="OverloadActionConstraint"/> to all actions in the controller.
|
||||
/// </summary>
|
||||
public interface IUseWebApiOverloading
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the model binding system should use ASP.NET Web API conventions for parameters of a controller's
|
||||
/// actions. For example, bind simple types from the URI.
|
||||
/// </summary>
|
||||
public interface IUseWebApiParameterConventions
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the controller is in the "api" area.
|
||||
/// </summary>
|
||||
public interface IUseWebApiRoutes
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates actions without attribute routes in a controller use ASP.NET Web API routing conventions.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
|
||||
public class UseWebApiActionConventionsAttribute : Attribute, IUseWebApiActionConventions
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates actions in a controller should be selected only if all non-optional parameters are satisfied. Applies
|
||||
/// the <see cref="OverloadActionConstraint"/> to all actions in the controller.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
|
||||
public class UseWebApiOverloadingAttribute : Attribute, IUseWebApiOverloading
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the model binding system should use ASP.NET Web API conventions for parameters of a controller's
|
||||
/// actions. For example, bind simple types from the URI.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
|
||||
public class UseWebApiParameterConventionsAttribute : Attribute, IUseWebApiParameterConventions
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the controller is in the "api" area.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
|
||||
public class UseWebApiRoutesAttribute : Attribute, IUseWebApiRoutes
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Mvc.ActionConstraints;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
public class WebApiActionConventionsApplicationModelConvention : IControllerModelConvention
|
||||
{
|
||||
private static readonly string[] SupportedHttpMethodConventions = new string[]
|
||||
{
|
||||
"GET",
|
||||
"PUT",
|
||||
"POST",
|
||||
"DELETE",
|
||||
"PATCH",
|
||||
"HEAD",
|
||||
"OPTIONS",
|
||||
};
|
||||
|
||||
public void Apply(ControllerModel controller)
|
||||
{
|
||||
if (controller == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(controller));
|
||||
}
|
||||
|
||||
if (IsConventionApplicable(controller))
|
||||
{
|
||||
var newActions = new List<ActionModel>();
|
||||
|
||||
foreach (var action in controller.Actions)
|
||||
{
|
||||
SetHttpMethodFromConvention(action);
|
||||
|
||||
// Action Name doesn't really come into play with attribute routed actions. However for a
|
||||
// non-attribute-routed action we need to create a 'named' version and an 'unnamed' version.
|
||||
if (!IsActionAttributeRouted(action))
|
||||
{
|
||||
var namedAction = action;
|
||||
|
||||
var unnamedAction = new ActionModel(namedAction);
|
||||
unnamedAction.RouteValues.Add("action", null);
|
||||
newActions.Add(unnamedAction);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var action in newActions)
|
||||
{
|
||||
controller.Actions.Add(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsConventionApplicable(ControllerModel controller)
|
||||
{
|
||||
return controller.Attributes.OfType<IUseWebApiActionConventions>().Any();
|
||||
}
|
||||
|
||||
private bool IsActionAttributeRouted(ActionModel action)
|
||||
{
|
||||
foreach (var controllerSelectorModel in action.Controller.Selectors)
|
||||
{
|
||||
if (controllerSelectorModel.AttributeRouteModel?.Template != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var actionSelectorModel in action.Selectors)
|
||||
{
|
||||
if (actionSelectorModel.AttributeRouteModel?.Template != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void SetHttpMethodFromConvention(ActionModel action)
|
||||
{
|
||||
foreach (var selector in action.Selectors)
|
||||
{
|
||||
if (selector.ActionConstraints.OfType<HttpMethodActionConstraint>().Count() > 0)
|
||||
{
|
||||
// If the HttpMethods are set from attributes, don't override it with the convention
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// The Method name is used to infer verb constraints. Changing the action name has no impact.
|
||||
foreach (var verb in SupportedHttpMethodConventions)
|
||||
{
|
||||
if (action.ActionMethod.Name.StartsWith(verb, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
foreach (var selector in action.Selectors)
|
||||
{
|
||||
selector.ActionConstraints.Add(new HttpMethodActionConstraint(new[] { verb }));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If no convention matches, then assume POST
|
||||
foreach (var actionSelectorModel in action.Selectors)
|
||||
{
|
||||
actionSelectorModel.ActionConstraints.Add(new HttpMethodActionConstraint(new[] { "POST" }));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
public class WebApiOverloadingApplicationModelConvention : IActionModelConvention
|
||||
{
|
||||
public void Apply(ActionModel action)
|
||||
{
|
||||
if (action == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(action));
|
||||
}
|
||||
|
||||
if (IsConventionApplicable(action.Controller))
|
||||
{
|
||||
foreach (var actionSelectorModel in action.Selectors)
|
||||
{
|
||||
actionSelectorModel.ActionConstraints.Add(new OverloadActionConstraint());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsConventionApplicable(ControllerModel controller)
|
||||
{
|
||||
return controller.Attributes.OfType<IUseWebApiOverloading>().Any();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Web.Http;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
public class WebApiParameterConventionsApplicationModelConvention : IActionModelConvention
|
||||
{
|
||||
public void Apply(ActionModel action)
|
||||
{
|
||||
if (action == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(action));
|
||||
}
|
||||
|
||||
if (IsConventionApplicable(action.Controller))
|
||||
{
|
||||
var optionalParameters = new HashSet<string>();
|
||||
var uriBindingSource = (new FromUriAttribute()).BindingSource;
|
||||
foreach (var parameter in action.Parameters)
|
||||
{
|
||||
// Some IBindingSourceMetadata attributes like ModelBinder attribute return null
|
||||
// as their binding source. Special case to ensure we do not ignore them.
|
||||
if (parameter.BindingInfo?.BindingSource != null ||
|
||||
parameter.Attributes.OfType<IBindingSourceMetadata>().Any())
|
||||
{
|
||||
// This has a binding behavior configured, just leave it alone.
|
||||
}
|
||||
else if (CanConvertFromString(parameter.ParameterInfo.ParameterType))
|
||||
{
|
||||
// Simple types are by-default from the URI.
|
||||
parameter.BindingInfo = parameter.BindingInfo ?? new BindingInfo();
|
||||
parameter.BindingInfo.BindingSource = uriBindingSource;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Complex types are by-default from the body.
|
||||
parameter.BindingInfo = parameter.BindingInfo ?? new BindingInfo();
|
||||
parameter.BindingInfo.BindingSource = BindingSource.Body;
|
||||
}
|
||||
|
||||
// For all non IOptionalBinderMetadata, which are not URL source (like FromQuery etc.) do not
|
||||
// participate in overload selection and hence are added to the hashset so that they can be
|
||||
// ignored in OverloadActionConstraint.
|
||||
var optionalMetadata = parameter.Attributes.OfType<IOptionalBinderMetadata>().SingleOrDefault();
|
||||
if (parameter.ParameterInfo.HasDefaultValue && parameter.BindingInfo.BindingSource == uriBindingSource ||
|
||||
optionalMetadata != null && optionalMetadata.IsOptional ||
|
||||
optionalMetadata == null && parameter.BindingInfo.BindingSource != uriBindingSource)
|
||||
{
|
||||
optionalParameters.Add(parameter.ParameterName);
|
||||
}
|
||||
}
|
||||
|
||||
action.Properties.Add("OptionalParameters", optionalParameters);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsConventionApplicable(ControllerModel controller)
|
||||
{
|
||||
return controller.Attributes.OfType<IUseWebApiParameterConventions>().Any();
|
||||
}
|
||||
|
||||
private static bool CanConvertFromString(Type destinationType)
|
||||
{
|
||||
destinationType = Nullable.GetUnderlyingType(destinationType) ?? destinationType;
|
||||
return IsSimpleType(destinationType) ||
|
||||
TypeDescriptor.GetConverter(destinationType).CanConvertFrom(typeof(string));
|
||||
}
|
||||
|
||||
private static bool IsSimpleType(Type type)
|
||||
{
|
||||
return type.GetTypeInfo().IsPrimitive ||
|
||||
type.Equals(typeof(decimal)) ||
|
||||
type.Equals(typeof(string)) ||
|
||||
type.Equals(typeof(DateTime)) ||
|
||||
type.Equals(typeof(Guid)) ||
|
||||
type.Equals(typeof(DateTimeOffset)) ||
|
||||
type.Equals(typeof(TimeSpan)) ||
|
||||
type.Equals(typeof(Uri));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
public class WebApiRoutesApplicationModelConvention : IControllerModelConvention
|
||||
{
|
||||
private readonly string _area;
|
||||
|
||||
public WebApiRoutesApplicationModelConvention(string area)
|
||||
{
|
||||
_area = area;
|
||||
}
|
||||
|
||||
public void Apply(ControllerModel controller)
|
||||
{
|
||||
if (controller == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(controller));
|
||||
}
|
||||
|
||||
if (IsConventionApplicable(controller))
|
||||
{
|
||||
controller.RouteValues.Add("area", _area);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsConventionApplicable(ControllerModel controller)
|
||||
{
|
||||
return controller.Attributes.OfType<IUseWebApiRoutes>().Any();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace System.Web.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// An action result that returns a <see cref="StatusCodes.Status500InternalServerError"/> response and
|
||||
/// performs content negotiation on an <see cref="HttpError"/> based on an <see cref="Exception"/>.
|
||||
/// </summary>
|
||||
public class ExceptionResult : ObjectResult
|
||||
{
|
||||
/// <summary>Initializes a new instance of the <see cref="ExceptionResult"/> class.</summary>
|
||||
/// <param name="exception">The exception to include in the error.</param>
|
||||
/// <param name="includeErrorDetail">
|
||||
/// <see langword="true"/> if the error should include exception messages; otherwise, <see langword="false"/>.
|
||||
/// </param>
|
||||
public ExceptionResult(Exception exception, bool includeErrorDetail)
|
||||
: base(new HttpError(exception, includeErrorDetail))
|
||||
{
|
||||
Exception = exception;
|
||||
IncludeErrorDetail = includeErrorDetail;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the exception to include in the error.
|
||||
/// </summary>
|
||||
public Exception Exception { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the error should include exception messages.
|
||||
/// </summary>
|
||||
public bool IncludeErrorDetail { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task ExecuteResultAsync(ActionContext context)
|
||||
{
|
||||
context.HttpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
|
||||
return base.ExecuteResultAsync(context);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http.Formatting;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
public static class FormDataCollectionExtensions
|
||||
{
|
||||
// This is a helper method to use Model Binding over a JQuery syntax.
|
||||
// Normalize from JQuery to MVC keys. The model binding infrastructure uses MVC keys
|
||||
// x[] --> x
|
||||
// [] --> ""
|
||||
// x[field] --> x.field, where field is not a number
|
||||
public static string NormalizeJQueryToMvc(string key)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
StringBuilder sb = null;
|
||||
var i = 0;
|
||||
while (true)
|
||||
{
|
||||
var indexOpen = key.IndexOf('[', i);
|
||||
if (indexOpen < 0)
|
||||
{
|
||||
// Fast path, no normalization needed.
|
||||
// This skips the string conversion and allocating the string builder.
|
||||
if (i == 0)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
sb = sb ?? new StringBuilder();
|
||||
sb.Append(key, i, key.Length - i);
|
||||
break; // no more brackets
|
||||
}
|
||||
|
||||
sb = sb ?? new StringBuilder();
|
||||
sb.Append(key, i, indexOpen - i); // everything up to "["
|
||||
|
||||
// Find closing bracket.
|
||||
var indexClose = key.IndexOf(']', indexOpen);
|
||||
if (indexClose == -1)
|
||||
{
|
||||
throw new ArgumentException(Resources.JQuerySyntaxMissingClosingBracket, nameof(key));
|
||||
}
|
||||
|
||||
if (indexClose == indexOpen + 1)
|
||||
{
|
||||
// Empty bracket. Signifies array. Just remove.
|
||||
}
|
||||
else
|
||||
{
|
||||
if (char.IsDigit(key[indexOpen + 1]))
|
||||
{
|
||||
// array index. Leave unchanged.
|
||||
sb.Append(key, indexOpen, indexClose - indexOpen + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Field name. Convert to dot notation.
|
||||
sb.Append('.');
|
||||
sb.Append(key, indexOpen + 1, indexClose - indexOpen - 1);
|
||||
}
|
||||
}
|
||||
|
||||
i = indexClose + 1;
|
||||
if (i >= key.Length)
|
||||
{
|
||||
break; // end of string
|
||||
}
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static IEnumerable<KeyValuePair<string, string>> GetJQueryNameValuePairs(
|
||||
this FormDataCollection formData)
|
||||
{
|
||||
if (formData == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(formData));
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
|
||||
foreach (var kv in formData)
|
||||
{
|
||||
ThrowIfMaxHttpCollectionKeysExceeded(count);
|
||||
|
||||
var key = NormalizeJQueryToMvc(kv.Key);
|
||||
var value = kv.Value ?? string.Empty;
|
||||
yield return new KeyValuePair<string, string>(key, value);
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ThrowIfMaxHttpCollectionKeysExceeded(int count)
|
||||
{
|
||||
if (count >= MediaTypeFormatter.MaxHttpCollectionKeys)
|
||||
{
|
||||
var message = Resources.FormatMaxHttpCollectionKeyLimitReached(
|
||||
MediaTypeFormatter.MaxHttpCollectionKeys,
|
||||
typeof(MediaTypeFormatter));
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
public class HttpResponseMessageOutputFormatter : IOutputFormatter
|
||||
{
|
||||
public bool CanWriteResult(OutputFormatterCanWriteContext context)
|
||||
{
|
||||
return context.Object is HttpResponseMessage;
|
||||
}
|
||||
|
||||
public async Task WriteAsync(OutputFormatterWriteContext context)
|
||||
{
|
||||
var response = context.HttpContext.Response;
|
||||
|
||||
var responseMessage = context.Object as HttpResponseMessage;
|
||||
if (responseMessage == null)
|
||||
{
|
||||
var message = Resources.FormatHttpResponseMessageFormatter_UnsupportedType(
|
||||
nameof(HttpResponseMessageOutputFormatter),
|
||||
nameof(HttpResponseMessage));
|
||||
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
using (responseMessage)
|
||||
{
|
||||
response.StatusCode = (int)responseMessage.StatusCode;
|
||||
|
||||
var responseFeature = context.HttpContext.Features.Get<IHttpResponseFeature>();
|
||||
if (responseFeature != null)
|
||||
{
|
||||
responseFeature.ReasonPhrase = responseMessage.ReasonPhrase;
|
||||
}
|
||||
|
||||
var responseHeaders = responseMessage.Headers;
|
||||
|
||||
// Ignore the Transfer-Encoding header if it is just "chunked".
|
||||
// We let the host decide about whether the response should be chunked or not.
|
||||
if (responseHeaders.TransferEncodingChunked == true &&
|
||||
responseHeaders.TransferEncoding.Count == 1)
|
||||
{
|
||||
responseHeaders.TransferEncoding.Clear();
|
||||
}
|
||||
|
||||
foreach (var header in responseHeaders)
|
||||
{
|
||||
response.Headers.Append(header.Key, header.Value.ToArray());
|
||||
}
|
||||
|
||||
if (responseMessage.Content != null)
|
||||
{
|
||||
var contentHeaders = responseMessage.Content.Headers;
|
||||
|
||||
// Copy the response content headers only after ensuring they are complete.
|
||||
// We ask for Content-Length first because HttpContent lazily computes this
|
||||
// and only afterwards writes the value into the content headers.
|
||||
var unused = contentHeaders.ContentLength;
|
||||
|
||||
foreach (var header in contentHeaders)
|
||||
{
|
||||
response.Headers.Append(header.Key, header.Value.ToArray());
|
||||
}
|
||||
|
||||
await responseMessage.Content.CopyToAsync(response.Body);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,285 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
using System.Xml.Serialization;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using ShimResources = Microsoft.IIS.Administration.WebApiCompatShim.Resources;
|
||||
|
||||
namespace System.Web.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a serializable container for storing error information. This information is stored
|
||||
/// as key/value pairs. The dictionary keys to look up standard error information are available
|
||||
/// on the <see cref="HttpErrorKeys"/> type.
|
||||
/// </summary>
|
||||
[XmlRoot("Error")]
|
||||
public sealed class HttpError : Dictionary<string, object>, IXmlSerializable
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpError"/> class.
|
||||
/// </summary>
|
||||
public HttpError()
|
||||
: base(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpError"/> class containing error message
|
||||
/// <paramref name="message"/>.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message to associate with this instance.</param>
|
||||
public HttpError(string message)
|
||||
: this()
|
||||
{
|
||||
if (message == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(message));
|
||||
}
|
||||
|
||||
Message = message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpError"/> class for <paramref name="exception"/>.
|
||||
/// </summary>
|
||||
/// <param name="exception">The exception to use for error information.</param>
|
||||
/// <param name="includeErrorDetail">
|
||||
/// <c>true</c> to include the exception information in the error;<c>false</c> otherwise.
|
||||
/// </param>
|
||||
public HttpError(Exception exception, bool includeErrorDetail)
|
||||
: this()
|
||||
{
|
||||
if (exception == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(exception));
|
||||
}
|
||||
|
||||
Message = ShimResources.HttpError_GenericError;
|
||||
|
||||
if (includeErrorDetail)
|
||||
{
|
||||
Add(HttpErrorKeys.ExceptionMessageKey, exception.Message);
|
||||
Add(HttpErrorKeys.ExceptionTypeKey, exception.GetType().FullName);
|
||||
Add(HttpErrorKeys.StackTraceKey, exception.StackTrace);
|
||||
if (exception.InnerException != null)
|
||||
{
|
||||
Add(HttpErrorKeys.InnerExceptionKey, new HttpError(exception.InnerException, includeErrorDetail));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpError"/> class for <paramref name="modelState"/>.
|
||||
/// </summary>
|
||||
/// <param name="modelState">The invalid model state to use for error information.</param>
|
||||
/// <param name="includeErrorDetail">
|
||||
/// <c>true</c> to include exception messages in the error; <c>false</c> otherwise.
|
||||
/// </param>
|
||||
public HttpError(ModelStateDictionary modelState, bool includeErrorDetail)
|
||||
: this()
|
||||
{
|
||||
if (modelState == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(modelState));
|
||||
}
|
||||
|
||||
if (modelState.IsValid)
|
||||
{
|
||||
throw new ArgumentException(ShimResources.HttpError_ValidModelState, nameof(modelState));
|
||||
}
|
||||
|
||||
Message = ShimResources.HttpError_BadRequest;
|
||||
|
||||
var modelStateError = new HttpError();
|
||||
foreach (KeyValuePair<string, ModelStateEntry> keyModelStatePair in modelState)
|
||||
{
|
||||
var key = keyModelStatePair.Key;
|
||||
var errors = keyModelStatePair.Value.Errors;
|
||||
if (errors != null && errors.Count > 0)
|
||||
{
|
||||
var errorMessages = errors.Select(error =>
|
||||
{
|
||||
if (includeErrorDetail && error.Exception != null)
|
||||
{
|
||||
return error.Exception.Message;
|
||||
}
|
||||
else
|
||||
{
|
||||
return
|
||||
string.IsNullOrEmpty(error.ErrorMessage) ?
|
||||
ShimResources.HttpError_GenericError :
|
||||
error.ErrorMessage;
|
||||
}
|
||||
}).ToArray();
|
||||
modelStateError.Add(key, errorMessages);
|
||||
}
|
||||
}
|
||||
|
||||
Add(HttpErrorKeys.ModelStateKey, modelStateError);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The high-level, user-visible message explaining the cause of the error. Information carried in this field
|
||||
/// should be considered public in that it will go over the wire regardless of the value of error detail
|
||||
/// policy. As a result care should be taken not to disclose sensitive information about the server or the
|
||||
/// application.
|
||||
/// </summary>
|
||||
public string Message
|
||||
{
|
||||
get { return GetPropertyValue<string>(HttpErrorKeys.MessageKey); }
|
||||
set { this[HttpErrorKeys.MessageKey] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ModelState"/> containing information about the errors that occurred during model binding.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The inclusion of <see cref="System.Exception"/> information carried in the <see cref="ModelState"/> is
|
||||
/// controlled by the error detail policy. All other information in the <see cref="ModelState"/>
|
||||
/// should be considered public in that it will go over the wire. As a result care should be taken not to
|
||||
/// disclose sensitive information about the server or the application.
|
||||
/// </remarks>
|
||||
public HttpError ModelState
|
||||
{
|
||||
get { return GetPropertyValue<HttpError>(HttpErrorKeys.ModelStateKey); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A detailed description of the error intended for the developer to understand exactly what failed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The inclusion of this field is controlled by the error detail policy. The
|
||||
/// field is expected to contain information about the server or the application that should not
|
||||
/// be disclosed broadly.
|
||||
/// </remarks>
|
||||
public string MessageDetail
|
||||
{
|
||||
get { return GetPropertyValue<string>(HttpErrorKeys.MessageDetailKey); }
|
||||
set { this[HttpErrorKeys.MessageDetailKey] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The message of the <see cref="System.Exception"/> if available.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The inclusion of this field is controlled by the error detail policy. The
|
||||
/// field is expected to contain information about the server or the application that should not
|
||||
/// be disclosed broadly.
|
||||
/// </remarks>
|
||||
public string ExceptionMessage
|
||||
{
|
||||
get { return GetPropertyValue<string>(HttpErrorKeys.ExceptionMessageKey); }
|
||||
set { this[HttpErrorKeys.ExceptionMessageKey] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The type of the <see cref="System.Exception"/> if available.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The inclusion of this field is controlled by the error detail policy. The
|
||||
/// field is expected to contain information about the server or the application that should not
|
||||
/// be disclosed broadly.
|
||||
/// </remarks>
|
||||
public string ExceptionType
|
||||
{
|
||||
get { return GetPropertyValue<string>(HttpErrorKeys.ExceptionTypeKey); }
|
||||
set { this[HttpErrorKeys.ExceptionTypeKey] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The stack trace information associated with this instance if available.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The inclusion of this field is controlled by the error detail policy. The
|
||||
/// field is expected to contain information about the server or the application that should not
|
||||
/// be disclosed broadly.
|
||||
/// </remarks>
|
||||
public string StackTrace
|
||||
{
|
||||
get { return GetPropertyValue<string>(HttpErrorKeys.StackTraceKey); }
|
||||
set { this[HttpErrorKeys.StackTraceKey] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The inner <see cref="System.Exception"/> associated with this instance if available.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The inclusion of this field is controlled by the error detail policy. The
|
||||
/// field is expected to contain information about the server or the application that should not
|
||||
/// be disclosed broadly.
|
||||
/// </remarks>
|
||||
public HttpError InnerException
|
||||
{
|
||||
get { return GetPropertyValue<HttpError>(HttpErrorKeys.InnerExceptionKey); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a particular property value from this error instance.
|
||||
/// </summary>
|
||||
/// <typeparam name="TValue">The type of the property.</typeparam>
|
||||
/// <param name="key">The name of the error property.</param>
|
||||
/// <returns>The value of the error property.</returns>
|
||||
public TValue GetPropertyValue<TValue>(string key)
|
||||
{
|
||||
object value;
|
||||
if (TryGetValue(key, out value) && value is TValue)
|
||||
{
|
||||
return (TValue)value;
|
||||
}
|
||||
|
||||
return default(TValue);
|
||||
}
|
||||
|
||||
XmlSchema IXmlSerializable.GetSchema()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
void IXmlSerializable.ReadXml(XmlReader reader)
|
||||
{
|
||||
if (reader.IsEmptyElement)
|
||||
{
|
||||
reader.Read();
|
||||
return;
|
||||
}
|
||||
|
||||
reader.ReadStartElement();
|
||||
while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
|
||||
{
|
||||
var key = XmlConvert.DecodeName(reader.LocalName);
|
||||
var value = reader.ReadInnerXml();
|
||||
|
||||
Add(key, value);
|
||||
reader.MoveToContent();
|
||||
}
|
||||
reader.ReadEndElement();
|
||||
}
|
||||
|
||||
void IXmlSerializable.WriteXml(XmlWriter writer)
|
||||
{
|
||||
foreach (var keyValuePair in this)
|
||||
{
|
||||
var key = keyValuePair.Key;
|
||||
var value = keyValuePair.Value;
|
||||
writer.WriteStartElement(XmlConvert.EncodeLocalName(key));
|
||||
if (value != null)
|
||||
{
|
||||
var innerError = value as HttpError;
|
||||
if (innerError == null)
|
||||
{
|
||||
writer.WriteValue(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
((IXmlSerializable)innerError).WriteXml(writer);
|
||||
}
|
||||
}
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace System.Web.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides keys to look up error information stored in the <see cref="HttpError"/> dictionary.
|
||||
/// </summary>
|
||||
public static class HttpErrorKeys
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a key for the Message.
|
||||
/// </summary>
|
||||
public static readonly string MessageKey = "Message";
|
||||
|
||||
/// <summary>
|
||||
/// Provides a key for the MessageDetail.
|
||||
/// </summary>
|
||||
public static readonly string MessageDetailKey = "MessageDetail";
|
||||
|
||||
/// <summary>
|
||||
/// Provides a key for the ModelState.
|
||||
/// </summary>
|
||||
public static readonly string ModelStateKey = "ModelState";
|
||||
|
||||
/// <summary>
|
||||
/// Provides a key for the ExceptionMessage.
|
||||
/// </summary>
|
||||
public static readonly string ExceptionMessageKey = "ExceptionMessage";
|
||||
|
||||
/// <summary>
|
||||
/// Provides a key for the ExceptionType.
|
||||
/// </summary>
|
||||
public static readonly string ExceptionTypeKey = "ExceptionType";
|
||||
|
||||
/// <summary>
|
||||
/// Provides a key for the StackTrace.
|
||||
/// </summary>
|
||||
public static readonly string StackTraceKey = "StackTrace";
|
||||
|
||||
/// <summary>
|
||||
/// Provides a key for the InnerException.
|
||||
/// </summary>
|
||||
public static readonly string InnerExceptionKey = "InnerException";
|
||||
|
||||
/// <summary>
|
||||
/// Provides a key for the MessageLanguage.
|
||||
/// </summary>
|
||||
public static readonly string MessageLanguageKey = "MessageLanguage";
|
||||
|
||||
/// <summary>
|
||||
/// Provides a key for the ErrorCode.
|
||||
/// </summary>
|
||||
public static readonly string ErrorCodeKey = "ErrorCode";
|
||||
}
|
||||
}
|
|
@ -1,520 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http.Formatting;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Web.Http;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.IIS.Administration.WebApiCompatShim;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using ShimResources = Microsoft.IIS.Administration.WebApiCompatShim.Resources;
|
||||
|
||||
namespace System.Net.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extension methods for the <see cref="HttpRequestMessage"/> class.
|
||||
/// </summary>
|
||||
public static class HttpRequestMessageExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper method that performs content negotiation and creates a <see cref="HttpResponseMessage"/>
|
||||
/// representing an error with an instance of <see cref="ObjectContent{T}"/> wrapping an
|
||||
/// <see cref="HttpError"/> with message <paramref name="message"/>. If no formatter is found, this method
|
||||
/// returns a response with status 406 NotAcceptable.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method requires that <paramref name="request"/> has been associated with an instance of
|
||||
/// <see cref="HttpContext"/>.
|
||||
/// </remarks>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="statusCode">The status code of the created response.</param>
|
||||
/// <param name="message">The error message.</param>
|
||||
/// <returns>
|
||||
/// An error response with error message <paramref name="message"/> and status code
|
||||
/// <paramref name="statusCode"/>.
|
||||
/// </returns>
|
||||
public static HttpResponseMessage CreateErrorResponse(
|
||||
this HttpRequestMessage request,
|
||||
HttpStatusCode statusCode,
|
||||
string message)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
}
|
||||
|
||||
if (message == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(message));
|
||||
}
|
||||
|
||||
return request.CreateErrorResponse(statusCode, new HttpError(message));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that performs content negotiation and creates a <see cref="HttpResponseMessage"/>
|
||||
/// representing an error with an instance of <see cref="ObjectContent{T}"/> wrapping an
|
||||
/// <see cref="HttpError"/> with error message <paramref name="message"/> for exception
|
||||
/// <paramref name="exception"/>. If no formatter is found, this method returns a response with status 406
|
||||
/// NotAcceptable.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method requires that <paramref name="request"/> has been associated with an instance of
|
||||
/// <see cref="HttpContext"/>.
|
||||
/// </remarks>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="statusCode">The status code of the created response.</param>
|
||||
/// <param name="message">The error message.</param>
|
||||
/// <param name="exception">The exception.</param>
|
||||
/// <returns>An error response for <paramref name="exception"/> with error message <paramref name="message"/>
|
||||
/// and status code <paramref name="statusCode"/>.</returns>
|
||||
public static HttpResponseMessage CreateErrorResponse(
|
||||
this HttpRequestMessage request,
|
||||
HttpStatusCode statusCode,
|
||||
string message,
|
||||
Exception exception)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
}
|
||||
|
||||
if (message == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(message));
|
||||
}
|
||||
|
||||
if (exception == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(exception));
|
||||
}
|
||||
|
||||
var error = new HttpError(exception, includeErrorDetail: false) { Message = message };
|
||||
return request.CreateErrorResponse(statusCode, error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that performs content negotiation and creates a <see cref="HttpResponseMessage"/>
|
||||
/// representing an error with an instance of <see cref="ObjectContent{T}"/> wrapping an
|
||||
/// <see cref="HttpError"/> for exception <paramref name="exception"/>. If no formatter is found, this method
|
||||
/// returns a response with status 406 NotAcceptable.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method requires that <paramref name="request"/> has been associated with an instance of
|
||||
/// <see cref="HttpContext"/>.
|
||||
/// </remarks>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="statusCode">The status code of the created response.</param>
|
||||
/// <param name="exception">The exception.</param>
|
||||
/// <returns>
|
||||
/// An error response for <paramref name="exception"/> with status code <paramref name="statusCode"/>.
|
||||
/// </returns>
|
||||
public static HttpResponseMessage CreateErrorResponse(
|
||||
this HttpRequestMessage request,
|
||||
HttpStatusCode statusCode,
|
||||
Exception exception)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
}
|
||||
|
||||
if (exception == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(exception));
|
||||
}
|
||||
|
||||
return request.CreateErrorResponse(statusCode, new HttpError(exception, includeErrorDetail: false));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that performs content negotiation and creates a <see cref="HttpResponseMessage"/>
|
||||
/// representing an error with an instance of <see cref="ObjectContent{T}"/> wrapping an
|
||||
/// <see cref="HttpError"/> for model state <paramref name="modelState"/>. If no formatter is found, this
|
||||
/// method returns a response with status 406 NotAcceptable.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method requires that <paramref name="request"/> has been associated with an instance of
|
||||
/// <see cref="HttpContext"/>.
|
||||
/// </remarks>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="statusCode">The status code of the created response.</param>
|
||||
/// <param name="modelState">The model state.</param>
|
||||
/// <returns>
|
||||
/// An error response for <paramref name="modelState"/> with status code <paramref name="statusCode"/>.
|
||||
/// </returns>
|
||||
public static HttpResponseMessage CreateErrorResponse(
|
||||
this HttpRequestMessage request,
|
||||
HttpStatusCode statusCode,
|
||||
ModelStateDictionary modelState)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
}
|
||||
|
||||
if (modelState == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(modelState));
|
||||
}
|
||||
|
||||
return request.CreateErrorResponse(statusCode, new HttpError(modelState, includeErrorDetail: false));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that performs content negotiation and creates a <see cref="HttpResponseMessage"/>
|
||||
/// representing an error with an instance of <see cref="ObjectContent{T}"/> wrapping <paramref name="error"/>
|
||||
/// as the content. If no formatter is found, this method returns a response with status 406 NotAcceptable.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method requires that <paramref name="request"/> has been associated with an instance of
|
||||
/// <see cref="HttpContext"/>.
|
||||
/// </remarks>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="statusCode">The status code of the created response.</param>
|
||||
/// <param name="error">The error to wrap.</param>
|
||||
/// <returns>
|
||||
/// An error response wrapping <paramref name="error"/> with status code <paramref name="statusCode"/>.
|
||||
/// </returns>
|
||||
public static HttpResponseMessage CreateErrorResponse(
|
||||
this HttpRequestMessage request,
|
||||
HttpStatusCode statusCode,
|
||||
HttpError error)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
}
|
||||
|
||||
if (error == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(error));
|
||||
}
|
||||
|
||||
return request.CreateResponse<HttpError>(statusCode, error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that performs content negotiation and creates a <see cref="HttpResponseMessage"/> with an
|
||||
/// instance of <see cref="ObjectContent{T}"/> as the content and <see cref="System.Net.HttpStatusCode.OK"/>
|
||||
/// as the status code if a formatter can be found. If no formatter is found, this method returns a response
|
||||
/// with status 406 NotAcceptable.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method requires that <paramref name="request"/> has been associated with an instance of
|
||||
/// <see cref="HttpContext"/>.
|
||||
/// </remarks>
|
||||
/// <typeparam name="T">The type of the value.</typeparam>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="value">The value to wrap. Can be <c>null</c>.</param>
|
||||
/// <returns>
|
||||
/// A response wrapping <paramref name="value"/> with <see cref="System.Net.HttpStatusCode.OK"/> status code.
|
||||
/// </returns>
|
||||
public static HttpResponseMessage CreateResponse<T>(this HttpRequestMessage request, T value)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
}
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
return request.CreateResponse<T>(HttpStatusCode.OK, value, formatters: null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that performs content negotiation and creates a <see cref="HttpResponseMessage"/> with an
|
||||
/// instance of <see cref="ObjectContent{T}"/> as the content if a formatter can be found. If no formatter is
|
||||
/// found, this method returns a response with status 406 NotAcceptable.
|
||||
/// configuration.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method requires that <paramref name="request"/> has been associated with an instance of
|
||||
/// <see cref="HttpContext"/>.
|
||||
/// </remarks>
|
||||
/// <typeparam name="T">The type of the value.</typeparam>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="statusCode">The status code of the created response.</param>
|
||||
/// <param name="value">The value to wrap. Can be <c>null</c>.</param>
|
||||
/// <returns>A response wrapping <paramref name="value"/> with <paramref name="statusCode"/>.</returns>
|
||||
public static HttpResponseMessage CreateResponse<T>(
|
||||
this HttpRequestMessage request,
|
||||
HttpStatusCode statusCode,
|
||||
T value)
|
||||
{
|
||||
return request.CreateResponse<T>(statusCode, value, formatters: null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that performs content negotiation and creates a <see cref="HttpResponseMessage"/> with an
|
||||
/// instance of <see cref="ObjectContent{T}"/> as the content if a formatter can be found. If no formatter is
|
||||
/// found, this method returns a response with status 406 NotAcceptable.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method will get the <see cref="HttpContext"/> instance associated with <paramref name="request"/>.
|
||||
/// </remarks>
|
||||
/// <typeparam name="T">The type of the value.</typeparam>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="statusCode">The status code of the created response.</param>
|
||||
/// <param name="value">The value to wrap. Can be <c>null</c>.</param>
|
||||
/// <param name="formatters">The set of <see cref="MediaTypeFormatter"/> objects from which to choose.</param>
|
||||
/// <returns>A response wrapping <paramref name="value"/> with <paramref name="statusCode"/>.</returns>
|
||||
public static HttpResponseMessage CreateResponse<T>(
|
||||
this HttpRequestMessage request,
|
||||
HttpStatusCode statusCode,
|
||||
T value,
|
||||
IEnumerable<MediaTypeFormatter> formatters)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
}
|
||||
|
||||
var context = GetHttpContext(request);
|
||||
|
||||
if (formatters == null)
|
||||
{
|
||||
// Get the default formatters from options
|
||||
var options = context.RequestServices.GetRequiredService<IOptions<WebApiCompatShimOptions>>();
|
||||
formatters = options.Value.Formatters;
|
||||
}
|
||||
|
||||
var contentNegotiator = context.RequestServices.GetRequiredService<IContentNegotiator>();
|
||||
|
||||
var result = contentNegotiator.Negotiate(typeof(T), request, formatters);
|
||||
if (result?.Formatter == null)
|
||||
{
|
||||
// Return a 406 when we're actually performing conneg and it fails to find a formatter.
|
||||
return new HttpResponseMessage(HttpStatusCode.NotAcceptable)
|
||||
{
|
||||
RequestMessage = request
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return request.CreateResponse(statusCode, value, result.Formatter, result.MediaType);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that creates a <see cref="HttpResponseMessage"/> with an <see cref="ObjectContent{T}"/>
|
||||
/// instance containing the provided <paramref name="value"/>. The given <paramref name="mediaType"/> is used
|
||||
/// to find an instance of <see cref="MediaTypeFormatter"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the value.</typeparam>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="statusCode">The status code of the created response.</param>
|
||||
/// <param name="value">The value to wrap. Can be <c>null</c>.</param>
|
||||
/// <param name="mediaType">
|
||||
/// The media type used to look up an instance of <see cref="MediaTypeFormatter"/>.
|
||||
/// </param>
|
||||
/// <returns>A response wrapping <paramref name="value"/> with <paramref name="statusCode"/>.</returns>
|
||||
public static HttpResponseMessage CreateResponse<T>(
|
||||
this HttpRequestMessage request,
|
||||
HttpStatusCode statusCode,
|
||||
T value,
|
||||
string mediaType)
|
||||
{
|
||||
return request.CreateResponse(statusCode, value, new MediaTypeHeaderValue(mediaType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that creates a <see cref="HttpResponseMessage"/> with an <see cref="ObjectContent{T}"/>
|
||||
/// instance containing the provided <paramref name="value"/>. The given <paramref name="mediaType"/> is used
|
||||
/// to find an instance of <see cref="MediaTypeFormatter"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the value.</typeparam>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="statusCode">The status code of the created response.</param>
|
||||
/// <param name="value">The value to wrap. Can be <c>null</c>.</param>
|
||||
/// <param name="mediaType">
|
||||
/// The media type used to look up an instance of <see cref="MediaTypeFormatter"/>.
|
||||
/// </param>
|
||||
/// <returns>A response wrapping <paramref name="value"/> with <paramref name="statusCode"/>.</returns>
|
||||
public static HttpResponseMessage CreateResponse<T>(
|
||||
this HttpRequestMessage request,
|
||||
HttpStatusCode statusCode,
|
||||
T value,
|
||||
MediaTypeHeaderValue mediaType)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
}
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
if (mediaType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(mediaType));
|
||||
}
|
||||
|
||||
var context = GetHttpContext(request);
|
||||
|
||||
// Get the default formatters from options
|
||||
var options = context.RequestServices.GetRequiredService<IOptions<WebApiCompatShimOptions>>();
|
||||
var formatters = options.Value.Formatters;
|
||||
|
||||
var formatter = formatters.FindWriter(typeof(T), mediaType);
|
||||
if (formatter == null)
|
||||
{
|
||||
var message = ShimResources.FormatHttpRequestMessage_CouldNotFindMatchingFormatter(
|
||||
mediaType.ToString(),
|
||||
value.GetType());
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
return request.CreateResponse(statusCode, value, formatter, mediaType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that creates a <see cref="HttpResponseMessage"/> with an <see cref="ObjectContent{T}"/>
|
||||
/// instance containing the provided <paramref name="value"/> and the given <paramref name="formatter"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the value.</typeparam>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="statusCode">The status code of the created response.</param>
|
||||
/// <param name="value">The value to wrap. Can be <c>null</c>.</param>
|
||||
/// <param name="formatter">The formatter to use.</param>
|
||||
/// <returns>A response wrapping <paramref name="value"/> with <paramref name="statusCode"/>.</returns>
|
||||
public static HttpResponseMessage CreateResponse<T>(
|
||||
this HttpRequestMessage request,
|
||||
HttpStatusCode statusCode,
|
||||
T value,
|
||||
MediaTypeFormatter formatter)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
}
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
if (formatter == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(formatter));
|
||||
}
|
||||
|
||||
return request.CreateResponse(statusCode, value, formatter, (MediaTypeHeaderValue)null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that creates a <see cref="HttpResponseMessage"/> with an <see cref="ObjectContent{T}"/>
|
||||
/// instance containing the provided <paramref name="value"/> and the given <paramref name="formatter"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the value.</typeparam>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="statusCode">The status code of the created response.</param>
|
||||
/// <param name="value">The value to wrap. Can be <c>null</c>.</param>
|
||||
/// <param name="formatter">The formatter to use.</param>
|
||||
/// <param name="mediaType">
|
||||
/// The media type override to set on the response's content. Can be <c>null</c>.
|
||||
/// </param>
|
||||
/// <returns>A response wrapping <paramref name="value"/> with <paramref name="statusCode"/>.</returns>
|
||||
public static HttpResponseMessage CreateResponse<T>(
|
||||
this HttpRequestMessage request,
|
||||
HttpStatusCode statusCode,
|
||||
T value,
|
||||
MediaTypeFormatter formatter,
|
||||
string mediaType)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
}
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
if (formatter == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(formatter));
|
||||
}
|
||||
|
||||
var mediaTypeHeader = mediaType != null ? new MediaTypeHeaderValue(mediaType) : null;
|
||||
return request.CreateResponse(statusCode, value, formatter, mediaTypeHeader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that creates a <see cref="HttpResponseMessage"/> with an <see cref="ObjectContent{T}"/>
|
||||
/// instance containing the provided <paramref name="value"/> and the given <paramref name="formatter"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the value.</typeparam>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="statusCode">The status code of the created response.</param>
|
||||
/// <param name="value">The value to wrap. Can be <c>null</c>.</param>
|
||||
/// <param name="formatter">The formatter to use.</param>
|
||||
/// <param name="mediaType">
|
||||
/// The media type override to set on the response's content. Can be <c>null</c>.
|
||||
/// </param>
|
||||
/// <returns>A response wrapping <paramref name="value"/> with <paramref name="statusCode"/>.</returns>
|
||||
public static HttpResponseMessage CreateResponse<T>(
|
||||
this HttpRequestMessage request,
|
||||
HttpStatusCode statusCode,
|
||||
T value,
|
||||
MediaTypeFormatter formatter,
|
||||
MediaTypeHeaderValue mediaType)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
}
|
||||
|
||||
if (formatter == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(formatter));
|
||||
}
|
||||
|
||||
var response = new HttpResponseMessage(statusCode)
|
||||
{
|
||||
RequestMessage = request,
|
||||
};
|
||||
|
||||
response.Content = new ObjectContent<T>(value, formatter, mediaType);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private static HttpContext GetHttpContext(HttpRequestMessage request)
|
||||
{
|
||||
var context = request.GetProperty<HttpContext>(nameof(HttpContext));
|
||||
if (context == null)
|
||||
{
|
||||
var message = ShimResources.FormatHttpRequestMessage_MustHaveHttpContext(
|
||||
nameof(HttpRequestMessage),
|
||||
"HttpRequestMessageHttpContextExtensions.GetHttpRequestMessage");
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
private static T GetProperty<T>(this HttpRequestMessage request, string key)
|
||||
{
|
||||
try
|
||||
{
|
||||
_ = request.Options.TryGetValue<T>(new HttpRequestOptionsKey<T>(key), out T value);
|
||||
return value;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Net.Http;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
public class HttpRequestMessageFeature : IHttpRequestMessageFeature
|
||||
{
|
||||
private readonly HttpContext _httpContext;
|
||||
private HttpRequestMessage _httpRequestMessage;
|
||||
|
||||
public HttpRequestMessageFeature(HttpContext httpContext)
|
||||
{
|
||||
if (httpContext == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(httpContext));
|
||||
}
|
||||
|
||||
_httpContext = httpContext;
|
||||
}
|
||||
|
||||
public HttpRequestMessage HttpRequestMessage
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_httpRequestMessage == null)
|
||||
{
|
||||
_httpRequestMessage = CreateHttpRequestMessage(_httpContext);
|
||||
}
|
||||
|
||||
return _httpRequestMessage;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_httpRequestMessage = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static HttpRequestMessage CreateHttpRequestMessage(HttpContext httpContext)
|
||||
{
|
||||
var httpRequest = httpContext.Request;
|
||||
var uriString =
|
||||
httpRequest.Scheme + "://" +
|
||||
httpRequest.Host +
|
||||
httpRequest.PathBase +
|
||||
httpRequest.Path +
|
||||
httpRequest.QueryString;
|
||||
|
||||
var message = new HttpRequestMessage(new HttpMethod(httpRequest.Method), uriString);
|
||||
|
||||
// This allows us to pass the message through APIs defined in legacy code and then
|
||||
// operate on the HttpContext inside.
|
||||
message.Options.Set<HttpContext>(new HttpRequestOptionsKey<HttpContext>(nameof(HttpContext)),
|
||||
httpContext);
|
||||
|
||||
message.Content = new StreamContent(httpRequest.Body);
|
||||
|
||||
foreach (var header in httpRequest.Headers)
|
||||
{
|
||||
// Every header should be able to fit into one of the two header collections.
|
||||
// Try message.Headers first since that accepts more of them.
|
||||
if (!message.Headers.TryAddWithoutValidation(header.Key, (IEnumerable<string>)header.Value))
|
||||
{
|
||||
var added = message.Content.Headers.TryAddWithoutValidation(header.Key, (IEnumerable<string>)header.Value);
|
||||
Debug.Assert(added);
|
||||
}
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Net.Http;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
public static class HttpRequestMessageHttpContextExtensions
|
||||
{
|
||||
public static HttpRequestMessage GetHttpRequestMessage(this HttpContext httpContext)
|
||||
{
|
||||
var feature = httpContext.Features.Get<IHttpRequestMessageFeature>();
|
||||
if (feature == null)
|
||||
{
|
||||
feature = new HttpRequestMessageFeature(httpContext);
|
||||
httpContext.Features.Set(feature);
|
||||
}
|
||||
|
||||
return feature.HttpRequestMessage;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="IModelBinder"/> implementation to bind models of type <see cref="HttpRequestMessage"/>.
|
||||
/// </summary>
|
||||
public class HttpRequestMessageModelBinder : IModelBinder
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task BindModelAsync(ModelBindingContext bindingContext)
|
||||
{
|
||||
var model = bindingContext.HttpContext.GetHttpRequestMessage();
|
||||
bindingContext.ValidationState.Add(model, new ValidationStateEntry() { SuppressValidation = true });
|
||||
bindingContext.Result = ModelBindingResult.Success(model);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Net.Http;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="IModelBinderProvider"/> implementation to bind models of type <see cref="HttpRequestMessage"/>.
|
||||
/// </summary>
|
||||
public class HttpRequestMessageModelBinderProvider : IModelBinderProvider
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public IModelBinder GetBinder(ModelBinderProviderContext context)
|
||||
{
|
||||
if (context.Metadata.ModelType == typeof(HttpRequestMessage))
|
||||
{
|
||||
return new HttpRequestMessageModelBinder();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
public interface IHttpRequestMessageFeature
|
||||
{
|
||||
HttpRequestMessage HttpRequestMessage { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using ShimResources = Microsoft.IIS.Administration.WebApiCompatShim.Resources;
|
||||
|
||||
namespace System.Web.Http
|
||||
{
|
||||
public class HttpResponseException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpResponseException"/> class.
|
||||
/// </summary>
|
||||
/// <param name="statusCode">The status code of the response.</param>
|
||||
public HttpResponseException(HttpStatusCode statusCode)
|
||||
: this(new HttpResponseMessage(statusCode))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpResponseException"/> class.
|
||||
/// </summary>
|
||||
/// <param name="response">The response message.</param>
|
||||
public HttpResponseException(HttpResponseMessage response)
|
||||
: base(ShimResources.HttpResponseExceptionMessage)
|
||||
{
|
||||
if (response == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(response));
|
||||
}
|
||||
|
||||
Response = response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="HttpResponseMessage"/> to return to the client.
|
||||
/// </summary>
|
||||
public HttpResponseMessage Response { get; private set; }
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Web.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
/// <summary>
|
||||
/// An action filter that sets <see cref="ActionExecutedContext.Result"/> to an <see cref="ObjectResult"/>
|
||||
/// if the exception type is <see cref="HttpResponseException"/>.
|
||||
/// This filter runs immediately after the action.
|
||||
/// </summary>
|
||||
public class HttpResponseExceptionActionFilter : IActionFilter, IOrderedFilter
|
||||
{
|
||||
/// <inheritdoc />
|
||||
// Return a high number by default so that it runs closest to the action.
|
||||
public int Order { get; set; } = int.MaxValue - 10;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnActionExecuted(ActionExecutedContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
var httpResponseException = context.Exception as HttpResponseException;
|
||||
if (httpResponseException != null)
|
||||
{
|
||||
var request = context.HttpContext.GetHttpRequestMessage();
|
||||
var response = httpResponseException.Response;
|
||||
|
||||
if (response != null && response.RequestMessage == null)
|
||||
{
|
||||
response.RequestMessage = request;
|
||||
}
|
||||
|
||||
var objectResult = new ObjectResult(response)
|
||||
{
|
||||
DeclaredType = typeof(HttpResponseMessage)
|
||||
};
|
||||
|
||||
context.Result = objectResult;
|
||||
|
||||
// Its marked as handled as in webapi because an HttpResponseException
|
||||
// was considered as a 'success' response.
|
||||
context.ExceptionHandled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace System.Web.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// An action result that returns an empty <see cref="StatusCodes.Status500InternalServerError"/> response.
|
||||
/// </summary>
|
||||
public class InternalServerErrorResult : StatusCodeResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InternalServerErrorResult"/> class.
|
||||
/// </summary>
|
||||
public InternalServerErrorResult()
|
||||
: base(StatusCodes.Status500InternalServerError)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
namespace System.Web.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// An action result that returns a <see cref="StatusCodes.Status400BadRequest"/> response and performs
|
||||
/// content negotiation on an <see cref="HttpError"/> based on a <see cref="ModelStateDictionary"/>.
|
||||
/// </summary>
|
||||
public class InvalidModelStateResult : ObjectResult
|
||||
{
|
||||
/// <summary>Initializes a new instance of the <see cref="InvalidModelStateResult"/> class.</summary>
|
||||
/// <param name="modelState">The model state to include in the error.</param>
|
||||
/// <param name="includeErrorDetail">
|
||||
/// <see langword="true"/> if the error should include exception messages; otherwise, <see langword="false"/>.
|
||||
/// </param>
|
||||
public InvalidModelStateResult(ModelStateDictionary modelState, bool includeErrorDetail)
|
||||
: base(new HttpError(modelState, includeErrorDetail))
|
||||
{
|
||||
if (modelState == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(modelState));
|
||||
}
|
||||
|
||||
ModelState = modelState;
|
||||
IncludeErrorDetail = includeErrorDetail;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the model state to include in the error.
|
||||
/// </summary>
|
||||
public ModelStateDictionary ModelState { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the error should include exception messages.
|
||||
/// </summary>
|
||||
public bool IncludeErrorDetail { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task ExecuteResultAsync(ActionContext context)
|
||||
{
|
||||
context.HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||
return base.ExecuteResultAsync(context);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\build\sign.props" />
|
||||
<Import Project="..\..\build\version.props" />
|
||||
<Import Project="..\..\build\plugins.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<Description>Microsoft.IIS.Administration.WebApiCompatShim Class Library</Description>
|
||||
<TargetFramework>$(IISAdministrationTargetFramework)</TargetFramework>
|
||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<VersionPrefix>$(IISAdministrationVersion)</VersionPrefix>
|
||||
<Authors>Microsoft</Authors>
|
||||
<AssemblyName>Microsoft.IIS.Administration.WebApiCompatShim</AssemblyName>
|
||||
<PackageId>Microsoft.IIS.Administration.WebApiCompatShim</PackageId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App"/>
|
||||
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -1,40 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace System.Web.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// An action result that performs content negotiation.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of content in the entity body.</typeparam>
|
||||
public class NegotiatedContentResult<T> : ObjectResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NegotiatedContentResult{T}"/> class with the values provided.
|
||||
/// </summary>
|
||||
/// <param name="statusCode">The HTTP status code for the response message.</param>
|
||||
/// <param name="content">The content value to negotiate and format in the entity body.</param>
|
||||
public NegotiatedContentResult(HttpStatusCode statusCode, T content)
|
||||
: base(content)
|
||||
{
|
||||
StatusCode = (int)statusCode;
|
||||
Content = content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content value to negotiate and format in the entity body.
|
||||
/// </summary>
|
||||
public T Content { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task ExecuteResultAsync(ActionContext context)
|
||||
{
|
||||
context.HttpContext.Response.StatusCode = (int)StatusCode;
|
||||
return base.ExecuteResultAsync(context);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,193 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Net.Http.Formatting;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.ActionConstraints;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="IActionConstraint"/> limiting candidate actions to those for which the request satisfies all
|
||||
/// non-optional parameters.
|
||||
/// </summary>
|
||||
public class OverloadActionConstraint : IActionConstraint
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Order => int.MaxValue;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Accept(ActionConstraintContext context)
|
||||
{
|
||||
var candidates = context.Candidates.Select(c => new
|
||||
{
|
||||
Action = c,
|
||||
Parameters = GetOverloadableParameters(c),
|
||||
});
|
||||
|
||||
// Combined route value keys and query string keys. These are the values available for overload selection.
|
||||
var requestKeys = GetCombinedKeys(context.RouteContext);
|
||||
|
||||
// Group candidates by the highest number of keys, and then process them until we find an action
|
||||
// with all parameters satisfied.
|
||||
foreach (var group in candidates.GroupBy(c => c.Parameters?.Count ?? 0).OrderByDescending(g => g.Key))
|
||||
{
|
||||
var foundMatch = false;
|
||||
foreach (var candidate in group)
|
||||
{
|
||||
var allFound = true;
|
||||
if (candidate.Parameters != null)
|
||||
{
|
||||
foreach (var parameter in candidate.Parameters)
|
||||
{
|
||||
if (!requestKeys.Contains(parameter.Prefix))
|
||||
{
|
||||
if (candidate.Action.Action == context.CurrentCandidate.Action)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
allFound = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allFound)
|
||||
{
|
||||
foundMatch = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundMatch)
|
||||
{
|
||||
return group.Any(c => c.Action.Action == context.CurrentCandidate.Action);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<OverloadedParameter> GetOverloadableParameters(ActionSelectorCandidate candidate)
|
||||
{
|
||||
if (candidate.Action.Parameters == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var isOverloaded = false;
|
||||
foreach (var constraint in candidate.Constraints)
|
||||
{
|
||||
if (constraint is OverloadActionConstraint)
|
||||
{
|
||||
isOverloaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isOverloaded)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var parameters = new List<OverloadedParameter>();
|
||||
candidate.Action.Properties.TryGetValue("OptionalParameters", out var optionalParametersObject);
|
||||
var optionalParameters = (HashSet<string>)optionalParametersObject;
|
||||
foreach (var parameter in candidate.Action.Parameters)
|
||||
{
|
||||
// We only consider parameters that are marked as bound from the URL.
|
||||
var source = parameter.BindingInfo?.BindingSource;
|
||||
if (source == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((source.CanAcceptDataFrom(BindingSource.Path) ||
|
||||
source.CanAcceptDataFrom(BindingSource.Query)) &&
|
||||
CanConvertFromString(parameter.ParameterType))
|
||||
{
|
||||
if (optionalParameters != null)
|
||||
{
|
||||
var isOptional = optionalParameters.Contains(parameter.Name);
|
||||
if (isOptional)
|
||||
{
|
||||
// Optional parameters are ignored in overloading. If a parameter doesn't specify that it's
|
||||
// required then treat it as optional (MVC default). WebAPI parameters will all by-default
|
||||
// specify themselves as required unless they have a default value.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var prefix = parameter.BindingInfo?.BinderModelName ?? parameter.Name;
|
||||
|
||||
parameters.Add(new OverloadedParameter()
|
||||
{
|
||||
ParameterDescriptor = parameter,
|
||||
Prefix = prefix,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private static ISet<string> GetCombinedKeys(RouteContext routeContext)
|
||||
{
|
||||
var keys = new HashSet<string>(routeContext.RouteData.Values.Keys, StringComparer.OrdinalIgnoreCase);
|
||||
keys.Remove("controller");
|
||||
keys.Remove("action");
|
||||
|
||||
var queryString = routeContext.HttpContext.Request.QueryString.ToUriComponent();
|
||||
|
||||
if (queryString.Length > 0)
|
||||
{
|
||||
// We need to chop off the leading '?'
|
||||
var queryData = new FormDataCollection(queryString.Substring(1));
|
||||
|
||||
var queryNameValuePairs = queryData.GetJQueryNameValuePairs();
|
||||
|
||||
if (queryNameValuePairs != null)
|
||||
{
|
||||
foreach (var queryNameValuePair in queryNameValuePairs)
|
||||
{
|
||||
keys.Add(queryNameValuePair.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
private static bool CanConvertFromString(Type destinationType)
|
||||
{
|
||||
destinationType = Nullable.GetUnderlyingType(destinationType) ?? destinationType;
|
||||
return IsSimpleType(destinationType) ||
|
||||
TypeDescriptor.GetConverter(destinationType).CanConvertFrom(typeof(string));
|
||||
}
|
||||
|
||||
private static bool IsSimpleType(Type type)
|
||||
{
|
||||
return type.GetTypeInfo().IsPrimitive ||
|
||||
type.Equals(typeof(decimal)) ||
|
||||
type.Equals(typeof(string)) ||
|
||||
type.Equals(typeof(DateTime)) ||
|
||||
type.Equals(typeof(Guid)) ||
|
||||
type.Equals(typeof(DateTimeOffset)) ||
|
||||
type.Equals(typeof(TimeSpan)) ||
|
||||
type.Equals(typeof(Uri));
|
||||
}
|
||||
|
||||
private class OverloadedParameter
|
||||
{
|
||||
public ParameterDescriptor ParameterDescriptor { get; set; }
|
||||
|
||||
public string Prefix { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using WebApiShimResources = Microsoft.IIS.Administration.WebApiCompatShim.Resources;
|
||||
|
||||
namespace System.Web.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// An attribute that specifies that the value can be bound from the query string or route data.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
|
||||
public class FromUriAttribute :
|
||||
Attribute,
|
||||
IOptionalBinderMetadata,
|
||||
IBindingSourceMetadata,
|
||||
IModelNameProvider
|
||||
{
|
||||
private static readonly BindingSource FromUriSource = CompositeBindingSource.Create(
|
||||
new BindingSource[] { BindingSource.Path, BindingSource.Query },
|
||||
WebApiShimResources.BindingSource_URL);
|
||||
|
||||
/// <inheritdoc />
|
||||
public BindingSource BindingSource { get { return FromUriSource; } }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsOptional { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||
{
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// An type that designates an optional parameter for the purposes
|
||||
/// of ASP.NET Web API action overloading. Optional parameters do not participate in overloading, and
|
||||
/// do not have to have a value for the action to be selected.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This has no impact when used without ASP.NET Web API action overloading.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public interface IOptionalBinderMetadata
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the parameter participates in ASP.NET Web API action overloading. If
|
||||
/// <c>true</c>, the parameter does not participate in overloading. Otherwise, it does.
|
||||
/// </summary>
|
||||
bool IsOptional { get; }
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: TypeForwardedTo(typeof(System.Net.Http.Formatting.ContentNegotiationResult))]
|
||||
[assembly: TypeForwardedTo(typeof(System.Net.Http.Formatting.DefaultContentNegotiator))]
|
||||
[assembly: TypeForwardedTo(typeof(System.Net.Http.Formatting.FormDataCollection ))]
|
||||
[assembly: TypeForwardedTo(typeof(System.Net.Http.Formatting.IContentNegotiator))]
|
||||
[assembly: TypeForwardedTo(typeof(System.Net.Http.Formatting.MediaTypeFormatterMatch))]
|
||||
[assembly: TypeForwardedTo(typeof(System.Net.Http.Formatting.MediaTypeFormatterMatchRanking))]
|
|
@ -1,184 +0,0 @@
|
|||
// <auto-generated />
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
|
||||
internal static class Resources
|
||||
{
|
||||
private static readonly ResourceManager _resourceManager
|
||||
= new ResourceManager("Microsoft.IIS.Administration.WebApiCompatShim.Resources", typeof(Resources).GetTypeInfo().Assembly);
|
||||
|
||||
/// <summary>
|
||||
/// The request is invalid.
|
||||
/// </summary>
|
||||
internal static string HttpError_BadRequest
|
||||
{
|
||||
get => GetString("HttpError_BadRequest");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The request is invalid.
|
||||
/// </summary>
|
||||
internal static string FormatHttpError_BadRequest()
|
||||
=> GetString("HttpError_BadRequest");
|
||||
|
||||
/// <summary>
|
||||
/// An error has occurred.
|
||||
/// </summary>
|
||||
internal static string HttpError_GenericError
|
||||
{
|
||||
get => GetString("HttpError_GenericError");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An error has occurred.
|
||||
/// </summary>
|
||||
internal static string FormatHttpError_GenericError()
|
||||
=> GetString("HttpError_GenericError");
|
||||
|
||||
/// <summary>
|
||||
/// The model state is valid.
|
||||
/// </summary>
|
||||
internal static string HttpError_ValidModelState
|
||||
{
|
||||
get => GetString("HttpError_ValidModelState");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The model state is valid.
|
||||
/// </summary>
|
||||
internal static string FormatHttpError_ValidModelState()
|
||||
=> GetString("HttpError_ValidModelState");
|
||||
|
||||
/// <summary>
|
||||
/// Could not find a formatter matching the media type '{0}' that can write an instance of '{1}'.
|
||||
/// </summary>
|
||||
internal static string HttpRequestMessage_CouldNotFindMatchingFormatter
|
||||
{
|
||||
get => GetString("HttpRequestMessage_CouldNotFindMatchingFormatter");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Could not find a formatter matching the media type '{0}' that can write an instance of '{1}'.
|
||||
/// </summary>
|
||||
internal static string FormatHttpRequestMessage_CouldNotFindMatchingFormatter(object p0, object p1)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("HttpRequestMessage_CouldNotFindMatchingFormatter"), p0, p1);
|
||||
|
||||
/// <summary>
|
||||
/// The {0} instance is not properly initialized. Use {1} to create an {0} for the current request.
|
||||
/// </summary>
|
||||
internal static string HttpRequestMessage_MustHaveHttpContext
|
||||
{
|
||||
get => GetString("HttpRequestMessage_MustHaveHttpContext");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The {0} instance is not properly initialized. Use {1} to create an {0} for the current request.
|
||||
/// </summary>
|
||||
internal static string FormatHttpRequestMessage_MustHaveHttpContext(object p0, object p1)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("HttpRequestMessage_MustHaveHttpContext"), p0, p1);
|
||||
|
||||
/// <summary>
|
||||
/// The {0} only supports writing objects of type {1}.
|
||||
/// </summary>
|
||||
internal static string HttpResponseMessageFormatter_UnsupportedType
|
||||
{
|
||||
get => GetString("HttpResponseMessageFormatter_UnsupportedType");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The {0} only supports writing objects of type {1}.
|
||||
/// </summary>
|
||||
internal static string FormatHttpResponseMessageFormatter_UnsupportedType(object p0, object p1)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("HttpResponseMessageFormatter_UnsupportedType"), p0, p1);
|
||||
|
||||
/// <summary>
|
||||
/// The key is invalid JQuery syntax because it is missing a closing bracket.
|
||||
/// </summary>
|
||||
internal static string JQuerySyntaxMissingClosingBracket
|
||||
{
|
||||
get => GetString("JQuerySyntaxMissingClosingBracket");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The key is invalid JQuery syntax because it is missing a closing bracket.
|
||||
/// </summary>
|
||||
internal static string FormatJQuerySyntaxMissingClosingBracket()
|
||||
=> GetString("JQuerySyntaxMissingClosingBracket");
|
||||
|
||||
/// <summary>
|
||||
/// The number of keys in a NameValueCollection has exceeded the limit of '{0}'. You can adjust it by modifying the MaxHttpCollectionKeys property on the '{1}' class.
|
||||
/// </summary>
|
||||
internal static string MaxHttpCollectionKeyLimitReached
|
||||
{
|
||||
get => GetString("MaxHttpCollectionKeyLimitReached");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The number of keys in a NameValueCollection has exceeded the limit of '{0}'. You can adjust it by modifying the MaxHttpCollectionKeys property on the '{1}' class.
|
||||
/// </summary>
|
||||
internal static string FormatMaxHttpCollectionKeyLimitReached(object p0, object p1)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("MaxHttpCollectionKeyLimitReached"), p0, p1);
|
||||
|
||||
/// <summary>
|
||||
/// Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for details.
|
||||
/// </summary>
|
||||
internal static string HttpResponseExceptionMessage
|
||||
{
|
||||
get => GetString("HttpResponseExceptionMessage");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for details.
|
||||
/// </summary>
|
||||
internal static string FormatHttpResponseExceptionMessage()
|
||||
=> GetString("HttpResponseExceptionMessage");
|
||||
|
||||
/// <summary>
|
||||
/// Failed to generate a URL using route '{0}'.
|
||||
/// </summary>
|
||||
internal static string CreatedAtRoute_RouteFailed
|
||||
{
|
||||
get => GetString("CreatedAtRoute_RouteFailed");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Failed to generate a URL using route '{0}'.
|
||||
/// </summary>
|
||||
internal static string FormatCreatedAtRoute_RouteFailed(object p0)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("CreatedAtRoute_RouteFailed"), p0);
|
||||
|
||||
/// <summary>
|
||||
/// URL
|
||||
/// </summary>
|
||||
internal static string BindingSource_URL
|
||||
{
|
||||
get => GetString("BindingSource_URL");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// URL
|
||||
/// </summary>
|
||||
internal static string FormatBindingSource_URL()
|
||||
=> GetString("BindingSource_URL");
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
||||
System.Diagnostics.Debug.Assert(value != null);
|
||||
|
||||
if (formatterNames != null)
|
||||
{
|
||||
for (var i = 0; i < formatterNames.Length; i++)
|
||||
{
|
||||
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,153 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="HttpError_BadRequest" xml:space="preserve">
|
||||
<value>The request is invalid.</value>
|
||||
</data>
|
||||
<data name="HttpError_GenericError" xml:space="preserve">
|
||||
<value>An error has occurred.</value>
|
||||
</data>
|
||||
<data name="HttpError_ValidModelState" xml:space="preserve">
|
||||
<value>The model state is valid.</value>
|
||||
</data>
|
||||
<data name="HttpRequestMessage_CouldNotFindMatchingFormatter" xml:space="preserve">
|
||||
<value>Could not find a formatter matching the media type '{0}' that can write an instance of '{1}'.</value>
|
||||
</data>
|
||||
<data name="HttpRequestMessage_MustHaveHttpContext" xml:space="preserve">
|
||||
<value>The {0} instance is not properly initialized. Use {1} to create an {0} for the current request.</value>
|
||||
</data>
|
||||
<data name="HttpResponseMessageFormatter_UnsupportedType" xml:space="preserve">
|
||||
<value>The {0} only supports writing objects of type {1}.</value>
|
||||
</data>
|
||||
<data name="JQuerySyntaxMissingClosingBracket" xml:space="preserve">
|
||||
<value>The key is invalid JQuery syntax because it is missing a closing bracket.</value>
|
||||
</data>
|
||||
<data name="MaxHttpCollectionKeyLimitReached" xml:space="preserve">
|
||||
<value>The number of keys in a NameValueCollection has exceeded the limit of '{0}'. You can adjust it by modifying the MaxHttpCollectionKeys property on the '{1}' class.</value>
|
||||
</data>
|
||||
<data name="HttpResponseExceptionMessage" xml:space="preserve">
|
||||
<value>Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for details.</value>
|
||||
</data>
|
||||
<data name="CreatedAtRoute_RouteFailed" xml:space="preserve">
|
||||
<value>Failed to generate a URL using route '{0}'.</value>
|
||||
</data>
|
||||
<data name="BindingSource_URL" xml:space="preserve">
|
||||
<value>URL</value>
|
||||
</data>
|
||||
</root>
|
|
@ -1,34 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Net.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace System.Web.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// An action result that returns a specified response message.
|
||||
/// </summary>
|
||||
public class ResponseMessageResult : ObjectResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ResponseMessageResult"/> class.
|
||||
/// </summary>
|
||||
/// <param name="response">The response message.</param>
|
||||
public ResponseMessageResult(HttpResponseMessage response)
|
||||
: base(response)
|
||||
{
|
||||
if (response == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(response));
|
||||
}
|
||||
|
||||
Response = response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the response message.
|
||||
/// </summary>
|
||||
public HttpResponseMessage Response { get; private set; }
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.IIS.Administration.WebApiCompatShim;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Routing.Constraints;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
public static class WebApiCompatShimRouteBuilderExtensions
|
||||
{
|
||||
public static IRouteBuilder MapWebApiRoute(
|
||||
this IRouteBuilder routeCollectionBuilder,
|
||||
string name,
|
||||
string template)
|
||||
{
|
||||
return MapWebApiRoute(routeCollectionBuilder, name, template, defaults: null);
|
||||
}
|
||||
|
||||
public static IRouteBuilder MapWebApiRoute(
|
||||
this IRouteBuilder routeCollectionBuilder,
|
||||
string name,
|
||||
string template,
|
||||
object defaults)
|
||||
{
|
||||
return MapWebApiRoute(routeCollectionBuilder, name, template, defaults, constraints: null);
|
||||
}
|
||||
|
||||
public static IRouteBuilder MapWebApiRoute(
|
||||
this IRouteBuilder routeCollectionBuilder,
|
||||
string name,
|
||||
string template,
|
||||
object defaults,
|
||||
object constraints)
|
||||
{
|
||||
return MapWebApiRoute(routeCollectionBuilder, name, template, defaults, constraints, dataTokens: null);
|
||||
}
|
||||
|
||||
public static IRouteBuilder MapWebApiRoute(
|
||||
this IRouteBuilder routeCollectionBuilder,
|
||||
string name,
|
||||
string template,
|
||||
object defaults,
|
||||
object constraints,
|
||||
object dataTokens)
|
||||
{
|
||||
var mutableDefaults = ObjectToDictionary(defaults);
|
||||
mutableDefaults.Add("area", WebApiCompatShimOptionsSetup.DefaultAreaName);
|
||||
|
||||
var mutableConstraints = ObjectToDictionary(constraints);
|
||||
mutableConstraints.Add("area", new RequiredRouteConstraint());
|
||||
|
||||
return routeCollectionBuilder.MapRoute(name, template, mutableDefaults, mutableConstraints, dataTokens);
|
||||
}
|
||||
|
||||
private static IDictionary<string, object> ObjectToDictionary(object value)
|
||||
{
|
||||
var dictionary = value as IDictionary<string, object>;
|
||||
if (dictionary != null)
|
||||
{
|
||||
return new RouteValueDictionary(dictionary);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new RouteValueDictionary(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Net.Http.Formatting;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.IIS.Administration.WebApiCompatShim;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
public static class WebApiCompatShimMvcBuilderExtensions
|
||||
{
|
||||
public static IMvcBuilder AddWebApiConventions(this IMvcBuilder builder)
|
||||
{
|
||||
builder.Services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, WebApiCompatShimOptionsSetup>());
|
||||
builder.Services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IConfigureOptions<WebApiCompatShimOptions>, WebApiCompatShimOptionsSetup>());
|
||||
|
||||
builder.Services.TryAddSingleton<IContentNegotiator, DefaultContentNegotiator>();
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Linq;
|
||||
using System.Net.Http.Formatting;
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
public class WebApiCompatShimOptions
|
||||
{
|
||||
public WebApiCompatShimOptions()
|
||||
{
|
||||
// Start with an empty collection, our options setup will add the default formatters.
|
||||
Formatters = new MediaTypeFormatterCollection(Enumerable.Empty<MediaTypeFormatter>());
|
||||
}
|
||||
|
||||
public MediaTypeFormatterCollection Formatters { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Formatting;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.IIS.Administration.WebApiCompatShim
|
||||
{
|
||||
public class WebApiCompatShimOptionsSetup
|
||||
: IConfigureOptions<MvcOptions>, IConfigureOptions<WebApiCompatShimOptions>
|
||||
{
|
||||
public static readonly string DefaultAreaName = "api";
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public void Configure(MvcOptions options)
|
||||
{
|
||||
// Add webapi behaviors to controllers with the appropriate attributes
|
||||
options.Conventions.Add(new WebApiActionConventionsApplicationModelConvention());
|
||||
options.Conventions.Add(new WebApiParameterConventionsApplicationModelConvention());
|
||||
options.Conventions.Add(new WebApiOverloadingApplicationModelConvention());
|
||||
options.Conventions.Add(new WebApiRoutesApplicationModelConvention(area: DefaultAreaName));
|
||||
|
||||
// Add an action filter for handling the HttpResponseException.
|
||||
options.Filters.Add(new HttpResponseExceptionActionFilter());
|
||||
|
||||
// Add a model binder to be able to bind HttpRequestMessage
|
||||
options.ModelBinderProviders.Insert(0, new HttpRequestMessageModelBinderProvider());
|
||||
|
||||
// Add a formatter to write out an HttpResponseMessage to the response
|
||||
options.OutputFormatters.Insert(0, new HttpResponseMessageOutputFormatter());
|
||||
|
||||
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(HttpRequestMessage)));
|
||||
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(HttpResponseMessage)));
|
||||
}
|
||||
|
||||
public void Configure(WebApiCompatShimOptions options)
|
||||
{
|
||||
// Add the default formatters
|
||||
options.Formatters.AddRange(new MediaTypeFormatterCollection());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@ namespace Microsoft.IIS.Administration.WebServer.AppPools
|
|||
using Microsoft.AspNetCore.Authorization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
[Route("api/webserver/application-pools")]
|
||||
[RequireWebServer]
|
||||
public class AppPoolsController : ApiBaseController {
|
||||
private const string AUDIT_FIELDS = "*,model.recycling.log_events.private_memory,model.recycling.periodic_restart.private_memory";
|
||||
|
@ -46,7 +46,7 @@ namespace Microsoft.IIS.Administration.WebServer.AppPools
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.AppPoolName)]
|
||||
public object Get(string id) {
|
||||
// Extract the name of the target app pool from the uuid specified in the request
|
||||
|
@ -92,7 +92,7 @@ namespace Microsoft.IIS.Administration.WebServer.AppPools
|
|||
return Created((string)AppPoolHelper.GetLocation(appPool.id), appPool);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit(fields: AUDIT_FIELDS, maskedFields: MASKED_FIELDS)]
|
||||
public void Delete(string id)
|
||||
{
|
||||
|
@ -110,7 +110,7 @@ namespace Microsoft.IIS.Administration.WebServer.AppPools
|
|||
}
|
||||
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit(fields: AUDIT_FIELDS, maskedFields: MASKED_FIELDS)]
|
||||
[ResourceInfo(Name = Defines.AppPoolName)]
|
||||
public async Task<object> Patch(string id, [FromBody] dynamic model)
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace Microsoft.IIS.Administration.WebServer.Applications {
|
|||
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/webapps")]
|
||||
public class ApplicationsController : ApiBaseController
|
||||
{
|
||||
private IFileProvider _fileProvider;
|
||||
|
@ -69,7 +70,7 @@ namespace Microsoft.IIS.Administration.WebServer.Applications {
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.WebAppName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
@ -123,7 +124,7 @@ namespace Microsoft.IIS.Administration.WebServer.Applications {
|
|||
return Created((string)ApplicationHelper.GetLocation(application.id), application);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.WebAppName)]
|
||||
public object Patch(string id, [FromBody] dynamic model)
|
||||
|
@ -158,7 +159,7 @@ namespace Microsoft.IIS.Administration.WebServer.Applications {
|
|||
return application;
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public void Delete(string id)
|
||||
{
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authentication
|
|||
using Microsoft.IIS.Administration.Core.Utils;
|
||||
|
||||
[RequireGlobalModule("AnonymousAuthenticationModule", "Anonymous Authentication")]
|
||||
[Route("api/webserver/authentication/anonymous-authentication")]
|
||||
public class AnonAuthController : ApiBaseController
|
||||
{
|
||||
private const string HIDDEN_FIELDS = "model.password";
|
||||
|
@ -29,7 +30,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authentication
|
|||
return AnonymousAuthenticationHelper.ToJsonModel(site, path);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.AnonAuthenticationName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
@ -40,7 +41,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authentication
|
|||
return AnonymousAuthenticationHelper.ToJsonModel(site, authId.Path);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit(AuditAttribute.ALL, HIDDEN_FIELDS)]
|
||||
[ResourceInfo(Name = Defines.AnonAuthenticationName)]
|
||||
public object Patch(string id, [FromBody] dynamic model)
|
||||
|
@ -63,7 +64,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authentication
|
|||
return AnonymousAuthenticationHelper.ToJsonModel(site, authId.Path);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit(AuditAttribute.ALL, HIDDEN_FIELDS)]
|
||||
public void Delete(string id)
|
||||
{
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authentication
|
|||
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/authentication")]
|
||||
public class AuthenticationController : ApiBaseController
|
||||
{
|
||||
[HttpGet]
|
||||
|
@ -33,7 +34,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authentication
|
|||
return Environment.Hal.Apply(Defines.AuthenticationResource.Guid, obj);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.AuthenticationName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authentication
|
|||
using Microsoft.IIS.Administration.Core.Utils;
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/authentication/basic-authentication")]
|
||||
public class BasicAuthController : ApiBaseController
|
||||
{
|
||||
private const string DISPLAY_NAME = "Basic Authentication";
|
||||
|
@ -31,7 +32,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authentication
|
|||
return BasicAuthenticationHelper.ToJsonModel(site, path);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.BasicAuthenticationName)]
|
||||
[RequireGlobalModule(BasicAuthenticationHelper.MODULE, DISPLAY_NAME)]
|
||||
public object Get(string id)
|
||||
|
@ -43,7 +44,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authentication
|
|||
return BasicAuthenticationHelper.ToJsonModel(site, basicAuthId.Path);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.BasicAuthenticationName)]
|
||||
[RequireGlobalModule(BasicAuthenticationHelper.MODULE, DISPLAY_NAME)]
|
||||
|
@ -82,7 +83,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authentication
|
|||
return Created(BasicAuthenticationHelper.GetLocation(auth.id), auth);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public async Task Delete(string id)
|
||||
{
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authentication
|
|||
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/authentication/digest-authentication")]
|
||||
public class DigestAuthController : ApiBaseController
|
||||
{
|
||||
private const string DISPLAY_NAME = "Digest Authentication";
|
||||
|
@ -32,7 +33,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authentication
|
|||
return DigestAuthenticationHelper.ToJsonModel(site, path);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.DigestAuthenticationName)]
|
||||
[RequireGlobalModule(DigestAuthenticationHelper.MODULE, DISPLAY_NAME)]
|
||||
public object Get(string id)
|
||||
|
@ -44,7 +45,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authentication
|
|||
return DigestAuthenticationHelper.ToJsonModel(site, digestAuthId.Path);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.DigestAuthenticationName)]
|
||||
[RequireGlobalModule(DigestAuthenticationHelper.MODULE, DISPLAY_NAME)]
|
||||
|
@ -83,7 +84,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authentication
|
|||
return Created(DigestAuthenticationHelper.GetLocation(auth.id), auth);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public async Task Delete(string id)
|
||||
{
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authentication
|
|||
using Microsoft.IIS.Administration.Core.Utils;
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/authentication/windows-authentication")]
|
||||
public class WinAuthController : ApiBaseController
|
||||
{
|
||||
private const string DISPLAY_NAME = "Windows Authentication";
|
||||
|
@ -31,7 +32,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authentication
|
|||
return WindowsAuthenticationHelper.ToJsonModel(site, path);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.WindowsAuthenticationName)]
|
||||
[RequireGlobalModule(WindowsAuthenticationHelper.MODULE, DISPLAY_NAME)]
|
||||
public object Get(string id)
|
||||
|
@ -43,7 +44,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authentication
|
|||
return WindowsAuthenticationHelper.ToJsonModel(site, winAuthId.Path);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.WindowsAuthenticationName)]
|
||||
[RequireGlobalModule(WindowsAuthenticationHelper.MODULE, DISPLAY_NAME)]
|
||||
|
@ -82,7 +83,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authentication
|
|||
return Created(WindowsAuthenticationHelper.GetLocation(auth.id), auth);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public async Task Delete(string id)
|
||||
{
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authorization
|
|||
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/authorization")]
|
||||
public class AuthorizationController : ApiBaseController
|
||||
{
|
||||
private const string DISPLAY_NAME = "Authorization";
|
||||
|
@ -31,7 +32,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authorization
|
|||
return AuthorizationHelper.ToJsonModel(site, path);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.AuthorizationName)]
|
||||
[RequireGlobalModule(AuthorizationHelper.MODULE, DISPLAY_NAME)]
|
||||
public object Get(string id)
|
||||
|
@ -43,7 +44,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authorization
|
|||
return AuthorizationHelper.ToJsonModel(site, authId.Path);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.AuthorizationName)]
|
||||
[RequireGlobalModule(AuthorizationHelper.MODULE, DISPLAY_NAME)]
|
||||
|
@ -90,7 +91,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authorization
|
|||
return Created(AuthorizationHelper.GetLocation(auth.id), auth);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public async Task Delete(string id)
|
||||
{
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authorization
|
|||
using Web.Administration;
|
||||
|
||||
[RequireGlobalModule(AuthorizationHelper.MODULE, "Authorization")]
|
||||
[Route("api/webserver/authorization/rules")]
|
||||
public class RulesController : ApiBaseController
|
||||
{
|
||||
[HttpGet]
|
||||
|
@ -44,7 +45,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authorization
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.RuleName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
@ -105,7 +106,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authorization
|
|||
return Created(AuthorizationHelper.GetRuleLocation(r.id), r);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.RuleName)]
|
||||
public object Patch(string id, [FromBody] dynamic model)
|
||||
|
@ -134,7 +135,7 @@ namespace Microsoft.IIS.Administration.WebServer.Authorization
|
|||
return r;
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public void Delete(string id)
|
||||
{
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace Microsoft.IIS.Administration.WebServer.CentralCertificates
|
|||
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/centralized-certificates")]
|
||||
public class CentralCertsController : ApiBaseController
|
||||
{
|
||||
private const string HIDDEN_FIELDS = "model.identity.password,model.private_key_password";
|
||||
|
@ -35,7 +36,7 @@ namespace Microsoft.IIS.Administration.WebServer.CentralCertificates
|
|||
return LocationChanged(CentralCertHelper.GetLocation(), CentralCertHelper.ToJsonModel());
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.CentralCertsName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
@ -48,7 +49,7 @@ namespace Microsoft.IIS.Administration.WebServer.CentralCertificates
|
|||
return CentralCertHelper.ToJsonModel();
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[ResourceInfo(Name = Defines.CentralCertsName)]
|
||||
[Audit(AuditAttribute.ALL, HIDDEN_FIELDS)]
|
||||
public object Patch(string id, [FromBody] dynamic model)
|
||||
|
@ -66,6 +67,7 @@ namespace Microsoft.IIS.Administration.WebServer.CentralCertificates
|
|||
}
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("{id}")]
|
||||
[ResourceInfo(Name = Defines.CentralCertsName)]
|
||||
[Audit(AuditAttribute.ALL, HIDDEN_FIELDS)]
|
||||
public async Task<object> Post([FromBody] dynamic model)
|
||||
|
@ -76,7 +78,7 @@ namespace Microsoft.IIS.Administration.WebServer.CentralCertificates
|
|||
return CentralCertHelper.ToJsonModel();
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit(AuditAttribute.ALL, HIDDEN_FIELDS)]
|
||||
public async Task Delete(string id)
|
||||
{
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace Microsoft.IIS.Administration.WebServer.Compression
|
|||
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/http-response-compression")]
|
||||
public class CompressionController : ApiBaseController
|
||||
{
|
||||
private const string DISPLAY_NAME = "Compression";
|
||||
|
@ -44,7 +45,7 @@ namespace Microsoft.IIS.Administration.WebServer.Compression
|
|||
return LocationChanged(CompressionHelper.GetLocation(d.id), d);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.CompressionName)]
|
||||
[RequireGlobalModule(CompressionHelper.STATIC_MODULE, DISPLAY_NAME)]
|
||||
[RequireGlobalModule(CompressionHelper.DYNAMIC_MODULE, DISPLAY_NAME)]
|
||||
|
@ -57,7 +58,7 @@ namespace Microsoft.IIS.Administration.WebServer.Compression
|
|||
return CompressionHelper.ToJsonModel(site, compId.Path);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.CompressionName)]
|
||||
[RequireGlobalModule(CompressionHelper.STATIC_MODULE, DISPLAY_NAME)]
|
||||
|
@ -97,7 +98,7 @@ namespace Microsoft.IIS.Administration.WebServer.Compression
|
|||
return Created(CompressionHelper.GetLocation(compression.id), compression);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public async Task Delete(string id)
|
||||
{
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace Microsoft.IIS.Administration.WebServer.DefaultDocuments
|
|||
using Microsoft.IIS.Administration.Core.Utils;
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/default-documents")]
|
||||
public class DefaultDocumentController : ApiBaseController
|
||||
{
|
||||
private const string DISPLAY_NAME = "Default Document";
|
||||
|
@ -36,7 +37,7 @@ namespace Microsoft.IIS.Administration.WebServer.DefaultDocuments
|
|||
return LocationChanged(DefaultDocumentHelper.GetLocation(d.id), d);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.DefaultDocumentsName)]
|
||||
[RequireGlobalModule(DefaultDocumentHelper.MODULE, DISPLAY_NAME)]
|
||||
public object Get(string id)
|
||||
|
@ -49,7 +50,7 @@ namespace Microsoft.IIS.Administration.WebServer.DefaultDocuments
|
|||
return DefaultDocumentHelper.ToJsonModel(site, docId.Path);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.DefaultDocumentsName)]
|
||||
[RequireGlobalModule(DefaultDocumentHelper.MODULE, DISPLAY_NAME)]
|
||||
|
@ -96,7 +97,7 @@ namespace Microsoft.IIS.Administration.WebServer.DefaultDocuments
|
|||
return Created(DefaultDocumentHelper.GetLocation(settings.id), settings);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public async Task Delete(string id)
|
||||
{
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace Microsoft.IIS.Administration.WebServer.DefaultDocuments
|
|||
|
||||
|
||||
[RequireGlobalModule(DefaultDocumentHelper.MODULE, "Default Document")]
|
||||
[Route("api/webserver/default-documents/files")]
|
||||
public class DefaultDocumentFilesController : ApiBaseController
|
||||
{
|
||||
[HttpGet]
|
||||
|
@ -41,7 +42,7 @@ namespace Microsoft.IIS.Administration.WebServer.DefaultDocuments
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.EntryName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
@ -64,7 +65,7 @@ namespace Microsoft.IIS.Administration.WebServer.DefaultDocuments
|
|||
return FilesHelper.ToJsonModel(file, site, fileId.Path);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.EntryName)]
|
||||
public object Patch([FromBody] dynamic model, string id)
|
||||
|
@ -154,7 +155,7 @@ namespace Microsoft.IIS.Administration.WebServer.DefaultDocuments
|
|||
return Created(FilesHelper.GetLocation(f.id), f);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public void Delete(string id)
|
||||
{
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace Microsoft.IIS.Administration.WebServer.Delegation
|
|||
using Microsoft.IIS.Administration.Core.Utils;
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/feature-delegation")]
|
||||
public class DelegationController : ApiBaseController
|
||||
{
|
||||
[HttpGet]
|
||||
|
@ -30,7 +31,7 @@ namespace Microsoft.IIS.Administration.WebServer.Delegation
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.DelegationName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
@ -48,7 +49,7 @@ namespace Microsoft.IIS.Administration.WebServer.Delegation
|
|||
return DelegationHelper.SectionToJsonModel(section, site, sectionId.Path, sectionId.ConfigScope);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.DelegationName)]
|
||||
public object Patch(string id, [FromBody] dynamic model)
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace Microsoft.IIS.Administration.WebServer.DirectoryBrowsing
|
|||
using Microsoft.IIS.Administration.Core.Utils;
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/directory-browsing")]
|
||||
public class DirectoryBrowsingController : ApiBaseController
|
||||
{
|
||||
private const string DISPLAY_NAME = "Directory Browsing";
|
||||
|
@ -35,7 +36,7 @@ namespace Microsoft.IIS.Administration.WebServer.DirectoryBrowsing
|
|||
return LocationChanged(DirectoryBrowsingHelper.GetLocation(d.id), d);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.DirectoryBrowsingName)]
|
||||
[RequireGlobalModule(DirectoryBrowsingHelper.MODULE, DISPLAY_NAME)]
|
||||
public object Get(string id)
|
||||
|
@ -47,7 +48,7 @@ namespace Microsoft.IIS.Administration.WebServer.DirectoryBrowsing
|
|||
return DirectoryBrowsingHelper.ToJsonModel(site, dirbId.Path);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.DirectoryBrowsingName)]
|
||||
[RequireGlobalModule(DirectoryBrowsingHelper.MODULE, DISPLAY_NAME)]
|
||||
|
@ -85,7 +86,7 @@ namespace Microsoft.IIS.Administration.WebServer.DirectoryBrowsing
|
|||
return Created(DirectoryBrowsingHelper.GetLocation(settings.id), settings);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public async Task Delete(string id)
|
||||
{
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace Microsoft.IIS.Administration.WebServer.Files
|
|||
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/files")]
|
||||
public class WsFilesController : ApiBaseController
|
||||
{
|
||||
private const string _units = "files";
|
||||
|
@ -112,7 +113,7 @@ namespace Microsoft.IIS.Administration.WebServer.Files
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.FileName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace Microsoft.IIS.Administration.WebServer.Handlers
|
|||
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/http-handlers/entries")]
|
||||
public class HandlerMappingsController : ApiBaseController
|
||||
{
|
||||
[HttpGet]
|
||||
|
@ -45,7 +46,7 @@ namespace Microsoft.IIS.Administration.WebServer.Handlers
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.EntryName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
@ -102,7 +103,7 @@ namespace Microsoft.IIS.Administration.WebServer.Handlers
|
|||
return Created(MappingsHelper.GetLocation(m.id), m);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.EntryName)]
|
||||
public object Patch(string id, [FromBody] dynamic model)
|
||||
|
@ -139,7 +140,7 @@ namespace Microsoft.IIS.Administration.WebServer.Handlers
|
|||
return m;
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public void Delete(string id)
|
||||
{
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace Microsoft.IIS.Administration.WebServer.Handlers
|
|||
using Microsoft.IIS.Administration.Core.Utils;
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/http-handlers")]
|
||||
public class HandlersController : ApiBaseController
|
||||
{
|
||||
[HttpGet]
|
||||
|
@ -31,7 +32,7 @@ namespace Microsoft.IIS.Administration.WebServer.Handlers
|
|||
return LocationChanged(HandlersHelper.GetLocation(d.id), d);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.HandlersName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
@ -46,7 +47,7 @@ namespace Microsoft.IIS.Administration.WebServer.Handlers
|
|||
return HandlersHelper.ToJsonModel(site, handlersId.Path);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.HandlersName)]
|
||||
public object Patch(string id, [FromBody] dynamic model)
|
||||
|
@ -75,7 +76,7 @@ namespace Microsoft.IIS.Administration.WebServer.Handlers
|
|||
return HandlersHelper.ToJsonModel(site, handlersId.Path);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public void Delete(string id)
|
||||
{
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpRedirect
|
|||
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/http-redirect")]
|
||||
public class HttpRedirectController : ApiBaseController
|
||||
{
|
||||
private const string DISPLAY_NAME = "HTTP Redirect";
|
||||
|
@ -36,7 +37,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpRedirect
|
|||
return LocationChanged(RedirectHelper.GetLocation(d.id), d);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.HttpRedirectName)]
|
||||
[RequireGlobalModule(RedirectHelper.MODULE, DISPLAY_NAME)]
|
||||
public object Get(string id)
|
||||
|
@ -48,7 +49,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpRedirect
|
|||
return RedirectHelper.ToJsonModel(site, redId.Path);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.HttpRedirectName)]
|
||||
[RequireGlobalModule(RedirectHelper.MODULE, DISPLAY_NAME)]
|
||||
|
@ -92,7 +93,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpRedirect
|
|||
return Created(RedirectHelper.GetLocation(settings.id), settings);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public async Task Delete(string id)
|
||||
{
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpRequestTracing
|
|||
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/http-request-tracing")]
|
||||
public class HttpRequestTracingController : ApiBaseController
|
||||
{
|
||||
private IFileProvider _fileProvider;
|
||||
|
@ -43,7 +44,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpRequestTracing
|
|||
return LocationChanged(Helper.GetLocation(d.id), d);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.HttpRequestTracingName)]
|
||||
[RequireGlobalModule(Helper.TRACING_MODULE, Helper.DISPLAY_NAME)]
|
||||
[RequireGlobalModule(Helper.FAILED_REQUEST_TRACING_MODULE, Helper.DISPLAY_NAME)]
|
||||
|
@ -56,7 +57,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpRequestTracing
|
|||
return Helper.ToJsonModel(site, hrtId.Path);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[ResourceInfo(Name = Defines.HttpRequestTracingName)]
|
||||
[RequireGlobalModule(Helper.TRACING_MODULE, Helper.DISPLAY_NAME)]
|
||||
[RequireGlobalModule(Helper.FAILED_REQUEST_TRACING_MODULE, Helper.DISPLAY_NAME)]
|
||||
|
@ -94,7 +95,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpRequestTracing
|
|||
return Created(Helper.GetLocation(settings.id), settings);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public async Task Delete(string id)
|
||||
{
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpRequestTracing
|
|||
|
||||
[RequireGlobalModule(Helper.TRACING_MODULE, Helper.DISPLAY_NAME)]
|
||||
[RequireGlobalModule(Helper.FAILED_REQUEST_TRACING_MODULE, Helper.DISPLAY_NAME)]
|
||||
[Route("api/webserver/http-request-tracing/traces")]
|
||||
public class RequestTracesController : ApiBaseController
|
||||
{
|
||||
private IFileProvider _provider;
|
||||
|
@ -53,7 +54,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpRequestTracing
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.TraceName)]
|
||||
public async Task<object> Get(string id)
|
||||
{
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpRequestTracing
|
|||
|
||||
[RequireGlobalModule(Helper.TRACING_MODULE, Helper.DISPLAY_NAME)]
|
||||
[RequireGlobalModule(Helper.FAILED_REQUEST_TRACING_MODULE, Helper.DISPLAY_NAME)]
|
||||
[Route("api/webserver/http-request-tracing/providers")]
|
||||
public class TraceProvidersController : ApiBaseController
|
||||
{
|
||||
[HttpGet]
|
||||
|
@ -44,7 +45,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpRequestTracing
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.ProviderName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
@ -106,7 +107,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpRequestTracing
|
|||
return Created(ProvidersHelper.GetLocation(p.id), p);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.ProviderName)]
|
||||
public object Patch(string id, dynamic model)
|
||||
|
@ -145,7 +146,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpRequestTracing
|
|||
return prov;
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public void Delete(string id)
|
||||
{
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpRequestTracing
|
|||
|
||||
[RequireGlobalModule(Helper.TRACING_MODULE, Helper.DISPLAY_NAME)]
|
||||
[RequireGlobalModule(Helper.FAILED_REQUEST_TRACING_MODULE, Helper.DISPLAY_NAME)]
|
||||
[Route("api/webserver/http-request-tracing/rules")]
|
||||
public class TraceRulesController : ApiBaseController
|
||||
{
|
||||
[HttpGet]
|
||||
|
@ -44,7 +45,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpRequestTracing
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.RuleName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
@ -106,7 +107,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpRequestTracing
|
|||
return Created(RulesHelper.GetLocation(r.id), r);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.RuleName)]
|
||||
public object Patch(string id, dynamic model)
|
||||
|
@ -145,7 +146,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpRequestTracing
|
|||
return rle;
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public void Delete(string id)
|
||||
{
|
||||
|
|
|
@ -18,6 +18,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpResponseHeaders
|
|||
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/http-response-headers/custom-headers")]
|
||||
public class CustomHeadersController : ApiBaseController
|
||||
{
|
||||
[HttpGet]
|
||||
|
@ -44,7 +45,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpResponseHeaders
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.CustomHeaderName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
@ -106,7 +107,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpResponseHeaders
|
|||
return Created(CustomHeadersHelper.GetLocation(ch.id), ch);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.CustomHeaderName)]
|
||||
public object Patch(string id, dynamic model)
|
||||
|
@ -142,7 +143,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpResponseHeaders
|
|||
return ch;
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public void Delete(string id)
|
||||
{
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpResponseHeaders
|
|||
using Microsoft.IIS.Administration.Core.Utils;
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/http-response-headers")]
|
||||
public class HttpResponseHeadersController : ApiBaseController
|
||||
{
|
||||
[HttpGet]
|
||||
|
@ -31,7 +32,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpResponseHeaders
|
|||
return LocationChanged(HttpResponseHeadersHelper.GetLocation(d.id), d);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.ResponseHeadersName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
@ -46,7 +47,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpResponseHeaders
|
|||
return HttpResponseHeadersHelper.ToJsonModel(site, headerId.Path);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.ResponseHeadersName)]
|
||||
public object Patch(string id, [FromBody] dynamic model)
|
||||
|
@ -71,7 +72,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpResponseHeaders
|
|||
return HttpResponseHeadersHelper.ToJsonModel(site, headerId.Path);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public void Delete(string id)
|
||||
{
|
||||
|
|
|
@ -18,6 +18,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpResponseHeaders
|
|||
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/http-response-headers/redirect-headers")]
|
||||
public class RedirectHeadersController : ApiBaseController
|
||||
{
|
||||
[HttpGet]
|
||||
|
@ -44,7 +45,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpResponseHeaders
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.RedirectHeaderName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
@ -106,7 +107,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpResponseHeaders
|
|||
return Created(RedirectHeadersHelper.GetLocation(h.id), h);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.RedirectHeaderName)]
|
||||
public object Patch(string id, dynamic model)
|
||||
|
@ -145,7 +146,7 @@ namespace Microsoft.IIS.Administration.WebServer.HttpResponseHeaders
|
|||
}
|
||||
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public void Delete(string id)
|
||||
{
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace Microsoft.IIS.Administration.WebServer.IPRestrictions
|
|||
using Microsoft.IIS.Administration.Core.Utils;
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/ip-restrictions")]
|
||||
public class IPRestrictionController : ApiBaseController
|
||||
{
|
||||
private const string DISPLAY_NAME = "IP and Domain Restrictions";
|
||||
|
@ -36,7 +37,7 @@ namespace Microsoft.IIS.Administration.WebServer.IPRestrictions
|
|||
return LocationChanged(IPRestrictionsHelper.GetLocation(d.id), d);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.IpRestrictionsName)]
|
||||
[RequireGlobalModule(IPRestrictionsHelper.MODULE, DISPLAY_NAME)]
|
||||
public object Get(string id)
|
||||
|
@ -48,7 +49,7 @@ namespace Microsoft.IIS.Administration.WebServer.IPRestrictions
|
|||
return IPRestrictionsHelper.ToJsonModel(site, ipId.Path);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.IpRestrictionsName)]
|
||||
[RequireGlobalModule(IPRestrictionsHelper.MODULE, DISPLAY_NAME)]
|
||||
|
@ -85,7 +86,7 @@ namespace Microsoft.IIS.Administration.WebServer.IPRestrictions
|
|||
return Created(IPRestrictionsHelper.GetLocation(settings.id), settings);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public async Task Delete(string id)
|
||||
{
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace Microsoft.IIS.Administration.WebServer.IPRestrictions
|
|||
|
||||
|
||||
[RequireGlobalModule("IpRestrictionModule", "IP and Domain Restrictions")]
|
||||
[Route("api/webserver/ip-restrictions/entries")]
|
||||
public class IPRestrictionRulesController : ApiBaseController
|
||||
{
|
||||
[HttpGet]
|
||||
|
@ -46,7 +47,7 @@ namespace Microsoft.IIS.Administration.WebServer.IPRestrictions
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.EntryName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
@ -114,7 +115,7 @@ namespace Microsoft.IIS.Administration.WebServer.IPRestrictions
|
|||
return Created(IPRestrictionsHelper.GetRuleLocation(r.id), r);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.EntryName)]
|
||||
public object Patch(string id, [FromBody] dynamic model)
|
||||
|
@ -150,7 +151,7 @@ namespace Microsoft.IIS.Administration.WebServer.IPRestrictions
|
|||
return rle;
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public void Delete(string id)
|
||||
{
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Microsoft.IIS.Administration.WebServer.Info
|
|||
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/info")]
|
||||
public class WebServerInfoController : ApiBaseController
|
||||
{
|
||||
private IWebServerVersion _versionProvider;
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace Microsoft.IIS.Administration.WebServer.Logging
|
|||
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/logging")]
|
||||
public class LoggingController : ApiBaseController
|
||||
{
|
||||
private const string DISPLAY_NAME = "IIS Logging Tools";
|
||||
|
@ -42,7 +43,7 @@ namespace Microsoft.IIS.Administration.WebServer.Logging
|
|||
return LocationChanged(LoggingHelper.GetLocation(d.id), d);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.LoggingName)]
|
||||
[RequireGlobalModule(LoggingHelper.HTTP_LOGGING_MODULE, DISPLAY_NAME)]
|
||||
public object Get(string id)
|
||||
|
@ -58,7 +59,7 @@ namespace Microsoft.IIS.Administration.WebServer.Logging
|
|||
return LoggingHelper.ToJsonModel(site, logId.Path);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.LoggingName)]
|
||||
[RequireGlobalModule(LoggingHelper.HTTP_LOGGING_MODULE, DISPLAY_NAME)]
|
||||
|
@ -103,7 +104,7 @@ namespace Microsoft.IIS.Administration.WebServer.Logging
|
|||
return Created(LoggingHelper.GetLocation(settings.id), settings);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public async Task Delete(string id)
|
||||
{
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace Microsoft.IIS.Administration.WebServer.Modules
|
|||
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/global-modules")]
|
||||
public class GlobalModulesController : ApiBaseController
|
||||
{
|
||||
[HttpGet]
|
||||
|
@ -41,7 +42,7 @@ namespace Microsoft.IIS.Administration.WebServer.Modules
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.GlobalModuleName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
@ -78,7 +79,7 @@ namespace Microsoft.IIS.Administration.WebServer.Modules
|
|||
return Created(ModuleHelper.GetGlobalModuleLocation(gm.id), gm);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.GlobalModuleName)]
|
||||
public object Patch(string id, [FromBody] dynamic model)
|
||||
|
@ -99,11 +100,10 @@ namespace Microsoft.IIS.Administration.WebServer.Modules
|
|||
return ModuleHelper.GlobalModuleToJsonModel(module);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public void Delete(string id, [FromBody] dynamic model)
|
||||
public void Delete(string id)
|
||||
{
|
||||
model = DynamicHelper.ToJObject(model);
|
||||
GlobalModuleId moduleId = GlobalModuleId.CreateFromUuid(id);
|
||||
|
||||
GlobalModule module = ModuleHelper.GetGlobalModules().FirstOrDefault(m => m.Name.Equals(moduleId.Name));
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace Microsoft.IIS.Administration.WebServer.Modules
|
|||
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/http-modules/entries")]
|
||||
public class ModulesController : ApiBaseController {
|
||||
|
||||
[HttpGet]
|
||||
|
@ -44,7 +45,7 @@ namespace Microsoft.IIS.Administration.WebServer.Modules
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.ModuleEntryName)]
|
||||
public object Get(string id) {
|
||||
EntryId entryId = new EntryId(id);
|
||||
|
@ -143,7 +144,7 @@ namespace Microsoft.IIS.Administration.WebServer.Modules
|
|||
return Created(ModuleHelper.GetModuleEntryLocation(moduleEntry.id), moduleEntry);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.ModuleEntryName)]
|
||||
public object Patch(string id, [FromBody] dynamic model)
|
||||
|
@ -185,7 +186,7 @@ namespace Microsoft.IIS.Administration.WebServer.Modules
|
|||
return entry;
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public void Delete(string id)
|
||||
{
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace Microsoft.IIS.Administration.WebServer.Modules
|
|||
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/http-modules")]
|
||||
public class ModulesGeneralController : ApiBaseController
|
||||
{
|
||||
[HttpGet]
|
||||
|
@ -33,7 +34,7 @@ namespace Microsoft.IIS.Administration.WebServer.Modules
|
|||
return LocationChanged(ModuleHelper.GetModuleGroupLocation(d.id), d);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.ModulesName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
@ -49,7 +50,7 @@ namespace Microsoft.IIS.Administration.WebServer.Modules
|
|||
return ModuleHelper.ModuleFeatureToJsonModel(site, modulesId.Path);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.ModulesName)]
|
||||
public object Patch(string id, [FromBody] dynamic model)
|
||||
|
@ -94,7 +95,7 @@ namespace Microsoft.IIS.Administration.WebServer.Modules
|
|||
return ModuleHelper.ModuleFeatureToJsonModel(site, modulesId.Path);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public void Delete(string id)
|
||||
{
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace Microsoft.IIS.Administration.WebServer.Monitoring
|
|||
using System.Threading.Tasks;
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/application-pools/monitoring")]
|
||||
public class AppPoolMonitoringController : ApiBaseController
|
||||
{
|
||||
private IAppPoolMonitor _monitor;
|
||||
|
@ -36,7 +37,7 @@ namespace Microsoft.IIS.Administration.WebServer.Monitoring
|
|||
}
|
||||
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.AppPoolMonitoringName)]
|
||||
public async Task<object> Get(string id)
|
||||
{
|
||||
|
|
|
@ -4,11 +4,13 @@
|
|||
|
||||
namespace Microsoft.IIS.Administration.WebServer.Monitoring
|
||||
{
|
||||
using Core.Http;
|
||||
using Core.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.IIS.Administration.Core;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/monitoring")]
|
||||
public class WebServerMonitoringController : ApiBaseController
|
||||
{
|
||||
private IWebServerMonitor _monitor;
|
||||
|
@ -18,6 +20,7 @@ namespace Microsoft.IIS.Administration.WebServer.Monitoring
|
|||
_monitor = monitor;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ResourceInfo(Name = Defines.WebServerMonitoringName)]
|
||||
public async Task<object> Get()
|
||||
{
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace Microsoft.IIS.Administration.WebServer.Monitoring
|
|||
using System.Threading.Tasks;
|
||||
|
||||
[RequireWebServer]
|
||||
[Route("api/webserver/websites/monitoring")]
|
||||
public class WebSiteMonitoringController : ApiBaseController
|
||||
{
|
||||
private IWebSiteMonitor _monitor;
|
||||
|
@ -36,7 +37,7 @@ namespace Microsoft.IIS.Administration.WebServer.Monitoring
|
|||
}
|
||||
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.WebSiteMonitoringName)]
|
||||
public async Task<object> Get(string id)
|
||||
{
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace Microsoft.IIS.Administration.WebServer.RequestFiltering
|
|||
using Core.Http;
|
||||
|
||||
[RequireGlobalModule(RequestFilteringHelper.MODULE, RequestFilteringHelper.DISPLAY_NAME)]
|
||||
[Route("api/webserver/http-request-filtering/file-extensions")]
|
||||
public class FileNameExtensionsController : ApiBaseController
|
||||
{
|
||||
[HttpGet]
|
||||
|
@ -40,7 +41,7 @@ namespace Microsoft.IIS.Administration.WebServer.RequestFiltering
|
|||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet("{id}")]
|
||||
[ResourceInfo(Name = Defines.FileExtensionName)]
|
||||
public object Get(string id)
|
||||
{
|
||||
|
@ -107,7 +108,7 @@ namespace Microsoft.IIS.Administration.WebServer.RequestFiltering
|
|||
return Created(ExtensionsHelper.GetLocation(ext.id), ext);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
[HttpPatch("{id}")]
|
||||
[Audit]
|
||||
[ResourceInfo(Name = Defines.FileExtensionName)]
|
||||
public object Patch(string id, [FromBody] dynamic model)
|
||||
|
@ -146,7 +147,7 @@ namespace Microsoft.IIS.Administration.WebServer.RequestFiltering
|
|||
return ext;
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[HttpDelete("{id}")]
|
||||
[Audit]
|
||||
public void Delete(string id)
|
||||
{
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче