在Sitecore8.2解决方案中使用Swagger作为API管理工具

假设您的Sitecore解决方案需要一些API服务。显而易见的是使用.net Web API实现它们。有时,在构建消费应用程序时,理解API的各种方法对开发人员来说可能是一项挑战。

假设您的Sitecore解决方案需要一些API服务。显而易见的是使用.net Web API实现它们。有时,在构建消费应用程序时,理解API的各种方法对开发人员来说可能是一项挑战。Swagger  是RESTful API的机器可读表示, 支持交互式文档,客户端SDK生成和可发现性。

使用Swagger

使用Swagger为Web API生成良好的文档和帮助页面就像添加NuGet包一样简单。

只要Sitecore仍然是一个asp.net应用程序,我们就可以使用Swagger!所以我实现了一个Web API控制器,我希望在我的Sitecore实例中托管它并以某种方式记录它:

1
2
3
4
6
7
8
9
10
11
12
13
14
15
namespace Feature.WebApi.Controllers
{
    using System.Web.Http;
 
    [RoutePrefix("-/api/v1")]
    public class MyServicesApiController : ApiController
    {
        [HttpGet]
        [Route("hello-world")]
        public IHttpActionResult HelloWorld()
        {
            return this.Ok("Hello world");
        }
    }
}

好的,这是我的“hello world”API方法。现在我将使用nuget将Swagger安装到我的Feature.Swagger项目中:

1
install-package Swashbuckle

默认的nuget包将在/App_Start/SwaggerConfig.cs中创建启动配置。默认情况下,它使用WebActivator扩展将其绑定到应用程序启动,以便在初始化Web应用程序时执行配置。

默认情况下,它不能与Sitecore平稳运行,但我们可以使用少量配置使其正常工作。Swagger UI的入口点是{your.domain.com} / swagger我跑了,看下一张图:

在Sitecore8.2解决方案中使用Swagger作为API管理工具

为了解决它,我们需要修改/App_Start/SwaggerConfig.cs并取消注释下一行:

1
c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());

再次运行 - 我们看到下一个问题:

在Sitecore8.2解决方案中使用Swagger作为API管理工具

这次我们需要取消注释另一行配置:

1
c.UseFullTypeNameInSchemaIds();

好的,现在它已启动并运行,但是底部有一个annoing错误,表示存在架构验证错误。Swagger UI仍然有效,但我们真的不想看到任何错误消息吗?我们可以通过取消另外一行配置来绕过它:

1
c.DisableValidator();

在Sitecore8.2解决方案中使用Swagger作为API管理工具

Web API服务

现在它查找并运行,我甚至能够找到我的服务方法。但是,Sitecore有很多自己使用的Web API服务,很难找到我自己的服务。将Sitecore本机Web API控制器与我的分离是很好的。它支持API版本控制,从我的角度来看,这是我们如何分离它的方法之一。我们可以向SwaggerConfig添加一个方法,该方法将声明API的版本。

我将Sitecore服务称为版本“ sc ”,将我自己称为“ my_services ”:

1
2
3
4
6
private static bool ResolveVersionSupportByRouteConstraint(ApiDescription apiDesc, string targetApiVersion)
{
    if (apiDesc.Route.RouteTemplate.StartsWith("-/api/v1") && targetApiVersion == "my_services") return true;
    if (apiDesc.Route.RouteTemplate.StartsWith("sitecore") && targetApiVersion == "sc") return true;
    return false;
}

在配置中,我们需要注释/删除此行

1
c.SingleApiVersion("v1", "Feature.Swagger");

并添加这个:

1
2
3
4
6
7
c.MultipleApiVersions(
    ResolveVersionSupportByRouteConstraint,
    vc =>
    {
        vc.Version("my_services", "My services API (you can switch to Sitecore API /swagger/docs/sc)");
        vc.Version("sc", "Sitecore services (you can switch to My services API /swagger/docs/my_services)");
    });

现在我们为Sitecore API和My API提供了2个独立的视图。它们被Swagger UI视为API版本:

在Sitecore8.2解决方案中使用Swagger作为API管理工具

在Sitecore8.2解决方案中使用Swagger作为API管理工具

安装

或许,公开提供该文档并不是一个好主意,因为它会产生安全问题。因此,我们需要做的是在登录后隐藏Swagger UI,并使其仅供Sitecore管理员用户使用。我们可以重新使用Sitecore的默认登录页面。从我的角度来看,最好的方法是使用HTTP MessageHandlers。我们可以实现下一个消息处理器

1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
namespace Feature.Swagger
{
    using System;
    using System.Net;
    using System.Net.Http;
    using System.Threading;
    using System.Threading.Tasks;
    using Sitecore;
 
    public class SwaggerSitecoreAuthMessageHandler : DelegatingHandler
    {
        protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var isAuthenticated = Context.User?.IsAuthenticated ?? false;
            var isAdministrator = Context.User?.IsAdministrator ?? false;
 
            if (this.IsSwaggerRequest(request) && (!isAuthenticated || !isAdministrator))
            {
                var response = new HttpResponseMessage(HttpStatusCode.Redirect);
                var uri = request.RequestUri;
                var currentOrigin = uri.AbsoluteUri.Replace(uri.PathAndQuery, string.Empty);
                var logiPage = currentOrigin + @"/sitecore/login?returnurl=/swagger";
                response.Headers.Location = new Uri(logiPage);
                return Task.FromResult(response);
            }
            else
            {
                return base.SendAsync(request, cancellationToken);
            }
        }
 
        private bool IsSwaggerRequest(HttpRequestMessage request)
        {
            return request.RequestUri.PathAndQuery.ToLowerInvariant().StartsWith("/swagger");
        }
    }
}

然后在SwaggerConfig类中添加一行,如下所示:

1
GlobalConfiguration.Configuration.MessageHandlers.Add(new SwaggerSitecoreAuthMessageHandler());

现在我们已成功将Swagger安装到Sitecore解决方案中。但是,正如我之前提到的,它使用WebActivator扩展,这更像是Web解决方案的反模式,我最好摆脱它,以保持螺旋原则。相反,我们可以使其更多Sitecore本地方式 - 在Sitecore初始化管道上运行配置。

所以首先我们要做的是删除这一行:

1
[assembly: PreApplicationStartMethod(typeof(SwaggerConfig), "Register")]

然后创建一个运行初始化的超简单初始化管道处理器:

1
2
3
4
6
7
8
9
10
11
12
namespace Feature.Swagger.Pipelines.Initialize
{
    using Sitecore.Pipelines;
 
    public class InitializeSwagger
    {
        public void Process(PipelineArgs args)
        {
            SwaggerConfig.Register();
        }
    }
}

当然我们需要将它添加到配置文件/App_Config/Include/Feature/Feature.Swagger.config中

1
2
3
4
6
7
8
9
10
<?xml version="1.0" encoding="utf-8" ?>
 
<sitecore>
<pipelines>
<initialize>
<processor type="Feature.Swagger.Pipelines.Initialize.InitializeSwagger, Feature.Swagger" />
</initialize>
</pipelines>
</sitecore>
</configuration>

最后,我的完整SwaggerConfig.cs文件如下所示:

1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
namespace Feature.Swagger
{
    using System.Web.Http;
    using System.Linq;
    using Swashbuckle.Application;
    using System.Web.Http.Description;
 
    public class SwaggerConfig
    {
        public static void Register()
        {
            var thisAssembly = typeof(SwaggerConfig).Assembly;
 
            GlobalConfiguration.Configuration.MessageHandlers.Add(new SwaggerSitecoreAuthMessageHandler());
 
            GlobalConfiguration.Configuration
                .EnableSwagger(c =>
                    {
                        c.MultipleApiVersions(
                            ResolveVersionSupportByRouteConstraint,
                            vc =>
                            {
                                vc.Version("my_services", "My services API (you can switch to Sitecore API /swagger/docs/sc)");
                                vc.Version("sc", "Sitecore services (you can switch to My services API /swagger/docs/my_services)");
                            });
 
                        c.UseFullTypeNameInSchemaIds();
 
                        c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
                    })
                .EnableSwaggerUi(c =>
                    {
                        c.DisableValidator();
                    });
        }
 
        private static bool ResolveVersionSupportByRouteConstraint(ApiDescription apiDesc, string targetApiVersion)
        {
            if (apiDesc.Route.RouteTemplate.StartsWith("-/api/v1") && targetApiVersion == "my_services") return true;
            if (apiDesc.Route.RouteTemplate.StartsWith("sitecore") && targetApiVersion == "sc") return true;
            return false;
        }
    }
}

就是这个。它与我们的Sitecore解决方案集成在一起。在他们的网站https://swagger.io上阅读有关所有Swagger功能的更多信息

我一直在使用Swagger和Sitecore 8.x以及Sitecore 9版本,一切正常!在这里查看我们的GitHub回购