找不到服务堆栈 Razor 视图

Service Stack Razor View Not Found

我在根视图文件夹中添加了 RazorPluginTest.cshtml(尝试了 wwwroot 以及 TestGet.cshtml)。这是一个 donet Core 项目。每当浏览到:/api/test 时,都会生成以下错误:

Snapshot of TestGet generated by ServiceStack on 6/3/2017 4:20:40 PM view json datasource from original url: http://localhost:51550/api/test? in other formats: json xml csv jsv Response Status Error CodeNullReferenceExceptionMessageObject reference not set to an instance of an object.Stack Trace[TestGet: 6/3/2017 4:20:40 PM]: [REQUEST: {}] System.NullReferenceException: Object reference not set to an instance of an object. at ServiceStack.Mvc.RazorFormat.FindView(IEnumerable1 viewNames) in /opt/lib/teamcity-agent/work/d09206570215629/src/ServiceStack.Mvc/RazorFormat.cs:line 174 at ServiceStack.Mvc.RazorFormat.ProcessRequest(IRequest req, IResponse res, Object dto) in /opt/lib/teamcity-agent/work/d09206570215629/src/ServiceStack.Mvc/RazorFormat.cs:line 138 at System.Linq.Enumerable.Any[TSource](IEnumerable1 source, Func`2 predicate) at ServiceStack.Formats.HtmlFormat.SerializeToStream(IRequest req, Object response, IResponse res) in /opt/lib/teamcity-agent/work/d09206570215629/src/ServiceStack/Formats/HtmlFormat.cs:line 63Errors

其他格式有效 (json/etc)。

 public class Test
 {
     public string ExternalId { get; set; }                
 }

  [Authenticate, Route("/test")]
  public class TestGet : IGet, IReturn<Test>
  {
  }

 public class TestService : Service
    {
        public IAutoQueryDb _autoQueryDb { get; set; }
        public IDbConnectionFactory _dbFactory { get; set; }

        public TestService(IDbConnectionFactory dbFactory)
        {
            _dbFactory = dbFactory;
        }

        public Test Get(TestGet request)
        {
            var test = new Test();
            test.ExternalId = "abc";
            return test;
        }

    }

Test.cshtml

@using App.Shared.DomainModel
@model Test

<div>Test</div>

AppHost.cs

using App.DomainServices;
using App.FontEnd.Infrastructure.Configuration;
using App.FontEnd.Infrastructure.Core;
using App.Shared.DomainModel;
using Funq;
using LightInject;
using ServiceStack;
using ServiceStack.Admin;
using ServiceStack.Api.Swagger;
using ServiceStack.Auth;
using ServiceStack.Caching;
using ServiceStack.Configuration;
using ServiceStack.Data;
using ServiceStack.Mvc;
using ServiceStack.OrmLite;
using ServiceStack.Validation;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;

namespace App.FrontEnd
{
    public class AppHost : AppHostBase
    {
        /// <summary>
        /// Base constructor requires a Name and Assembly where web service implementation is located
        /// </summary>
        public AppHost()
            : base("TestApi", typeof(CompanyService).GetAssembly())
        {

        }

        /// <summary>
        /// Application specific configuration
        /// This method should initialize any IoC resources utilized by your web service classes.
        /// </summary>
        public override void Configure(Container container)
        {


            this.GlobalRequestFilters.Add((httpReq, httpResp, requestDto) =>
            {
                var currentSession = httpReq.GetSession();
                if (currentSession != null)
                {
                    RequestContext.Instance.Items.Add("CurrentUserName", currentSession.UserName);
                    RequestContext.Instance.Items.Add("CurrentUserId", currentSession.UserAuthId);
                }
            });

            ServiceContainer LightContainer = new ServiceContainer();

            LightContainer.RegisterInstance<IDbConnectionFactory>
            (
                new OrmLiteConnectionFactory(
                    "removed",
                    SqlServer2014Dialect.Provider
                )
            );

            LightContainer.Register<IDbConnection>(c =>
                c.GetInstance<IDbConnectionFactory>().OpenDbConnection(),
                new PerScopeLifetime()
            );

            LightContainer.Register<OrmLiteAppSettings>(c =>
                new OrmLiteAppSettings(c.GetInstance<IDbConnectionFactory>()));           
            LightContainer.Register<ServiceStack.Web.IServiceGatewayFactory>(x => new ApiServiceGatewayFactory());
            container.Adapter = new LightInjectAdapter(LightContainer);

            var settings = LightContainer.GetInstance<OrmLiteAppSettings>();
            settings.InitSchema();
            AppSettings = new MultiAppSettings(
                settings
            );

            container.Register<ICacheClient>(new OrmLiteCacheClient
            {
                DbFactory = LightContainer.GetInstance<IDbConnectionFactory>()
            });
            var cacheclient = container.Resolve<ICacheClient>();
            cacheclient.InitSchema();

            AuthConfig(container, AppSettings);

            Plugins.Add(new RegistrationFeature());
            Plugins.Add(new SwaggerFeature());
            Plugins.Add(new RequestLogsFeature());
            Plugins.Add(new PostmanFeature());
            Plugins.Add(new CorsFeature(allowCredentials: true));
            Plugins.Add(new ValidationFeature());

            Plugins.Add(new RazorFormat());



            OrmLiteConfig.InsertFilter = (dbCmd, row) =>
            {
                var auditRow = row as CoreModel;
                if (auditRow != null)
                {
                    var currentDate = DateTime.UtcNow;
                    var insertUserId = RequestContext.Instance.Items["CurrentUserId"] as string;

                    auditRow.Id = Guid.NewGuid();
                    auditRow.CreatedDate = currentDate;
                    auditRow.CreatedBy = insertUserId;
                    auditRow.UpdatedDate = currentDate;
                    auditRow.UpdatedBy = insertUserId;
                }
            };

            OrmLiteConfig.UpdateFilter = (dbCmd, row) =>
            {
                var auditRow = row as CoreModel;

                if (auditRow != null)
                {
                    var updateUserId = RequestContext.Instance.Items["CurrentUserId"] as string;
                    auditRow.UpdatedDate = DateTime.UtcNow;
                    auditRow.UpdatedBy = updateUserId;
                }
            };

            var aq = new AutoQueryFeature { MaxLimit = 100, EnableAutoQueryViewer = true };
            aq.ImplicitConventions.Add("%neq", aq.ImplicitConventions["%NotEqualTo"]);
            aq.ImplicitConventions.Add("%eq", "{Field} = {Value}");
            Plugins.Add(aq);
            Plugins.Add(new AdminFeature());

            SetConfig(new HostConfig
            {
                HandlerFactoryPath = "api",
                DebugMode = true
            });

            container.CheckAdapterFirst = true;

            //Set up service stack validators
            container.ValidatorsSetup();
        }

        public void AuthConfig(Container container, IAppSettings settings)
        {
            Plugins.Add(new AuthFeature(() => new AuthUserSession(),
                new IAuthProvider[] {
                    new CredentialsAuthProvider(AppSettings),
                    new JwtAuthProvider(AppSettings)
                    {
                        AuthKeyBase64 = "abcdefgh"
                    },

                    new BasicAuthProvider()
            }));



            var authRepo = CreateOrmLiteAuthRepo(container, settings);


        }

        private static IUserAuthRepository CreateOrmLiteAuthRepo(Container container, IAppSettings appSettings)
        {
            //Store User Data into the referenced SqlServer database
            container.Register<IAuthRepository>(c =>
                new OrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>()));

            //Use OrmLite DB Connection to persist the UserAuth and AuthProvider info
            var authRepo = (OrmLiteAuthRepository)container.Resolve<IAuthRepository>();
            //If using and RDBMS to persist UserAuth, we must create required tables
            if (appSettings.Get("RecreateAuthTables", false))
                authRepo.DropAndReCreateTables(); //Drop and re-create all Auth and registration tables
            else
                authRepo.InitSchema(); //Create only the missing tables

            return authRepo;
        }
    }
}

我已经创建了一个最小的可验证 MVC 测试项目来模拟您的配置,它按预期工作在:https://github.com/NetCoreApps/scratch/tree/master/src/RazorApi

它包括 same Test Services,(无 [Authenticate] 属性):

public class Test
{
    public string ExternalId { get; set; }
}

[Route("/test")]
public class TestGet : IGet, IReturn<Test>
{
}

public class TestService : Service
{
    public Test Get(TestGet request)
    {
        var test = new Test { ExternalId = "abc" };
        return test;
    }
}

minimal AppHost configuration 只是将 HandlerFactoryPath 设置为 api 并注册 ServiceStack 的 RazorFormat 插件:

public class AppHost : AppHostBase
{
    public AppHost() 
        : base("ServiceStack + .NET Core", typeof(MyServices).GetTypeInfo().Assembly) {}

    public override void Configure(Funq.Container container)
    {
        SetConfig(new HostConfig
        {
            HandlerFactoryPath = "api",
            DebugMode = true,
        });

        Plugins.Add(new RazorFormat());
    }
}

Test.cshtml 保持在 /Views/Test.cshtml:

@model Test
@{
    Layout = "_Layout";
}

<h1>Test.cshtml</h1>

<p>@Model.ExternalId</p>

调用时执行的 Razor 视图按预期工作:

http://localhost:5000/api/test

重命名以匹配 TestGet.cshtml 处的请求 DTO 时也有效。

由于该问题似乎与您的项目有关,我会将您的布局与裸布局进行比较 RazorApi Github Project 以查看是否可以发现任何差异,否则我建议注释掉配置以使其正常工作state 然后一次取消注释部分,找出导致问题的配置。