ServiceStack Razor (self-hosted) with embedded ima

2019-07-02 15:20发布

问题:

I have a self-hosted WebService/WebApplication using the wonderful Service Stack.

My views are embedded in the DLL, and so are the images. I am using the ResourceVirtualPathProvider code from GitHub. It finds the index page and layouts correctly, but it can't find the embedded images/css (probably obviously).

How would I go about configuring the Razor plugin to search the path providers. I've checked in debug mode and the path providers have found all the css and images. They're just not getting routed.

EDIT

I have tried setting the AppHost's VirtualPathProvider property to the same provider that I configured the RazorFormat plugin with, but to no avail.

LAST EDIT

Thanks to Mythz's response, I have now got this working and provide the solution below:

  1. Firstly (and I had this before), I used the Embedded code from GitHub to create resource virtual path providers, directories, and files.

  2. Implemented a VirtualFileHandler:

    public sealed class VirtualFileHandler : IHttpHandler, IServiceStackHttpHandler
    {
    private IVirtualFile _file;
    
    
    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="file">File to serve up</param>
    public VirtualFileHandler(IVirtualFile file)
    {
        _file = file.ThrowIfDefault("file");
    }   // eo ctor
    
    
    public bool IsReusable { get { return false; } }
    
    
    public void ProcessRequest(HttpContext context)
    {
        ProcessRequest(new HttpRequestWrapper(null, context.Request),
                       new HttpResponseWrapper(context.Response),
                       null);
    }   // eo ProcessRequest
    
    public void ProcessRequest(IHttpRequest request, IHttpResponse response, string operationName)
    {
        try
        {
            response.ContentType = ALHEnvironment.GetMimeType(_file.Extension);
            using (Stream reader = _file.OpenRead())
            {
                byte[] data = reader.ReadFully();
                response.SetContentLength(data.Length);
                response.OutputStream.Write(data, 0, data.Length);
                response.OutputStream.Flush();
            }
        }
        catch (System.Net.HttpListenerException ex)
        {
            //Error: 1229 is "An operation was attempted on a nonexistent network connection"
            //This exception occures when http stream is terminated by the web browser.
            if (ex.ErrorCode == 1229)
                return;
            throw;
        }
    }   // eo ProcessRequest
    }   // eo class VirtualFileHandler
    
  3. Configured everything in my configuration function (the fact it is static is unique to my scenario, but it's effectively called from the regular AppHost's Configure function)

    protected static void Configure(WebHostConfiguration config)
    {
        _pathProvider = new MultiVirtualPathProvider(config.AppHost,
                                                     new ResourceVirtualPathProvider(config.AppHost, WebServiceContextBase.Instance.GetType()),
                                                     new ResourceVirtualPathProvider(config.AppHost, typeof(ResourceVirtualPathProvider)));
        config.Plugins.Add(new RazorFormat()
        {
            EnableLiveReload = false,
            VirtualPathProvider = _pathProvider
        });
    
    
        /*
         * We need to be able to locate other embedded resources other than views, such as CSS, javascript files,
         * and images.  To do this, we implement a CatchAllHandler and locate the resource ourselves
         */
        config.AppHost.CatchAllHandlers.Add((httpMethod, pathInfo, filePath) =>
        {
            IVirtualFile file = _pathProvider.GetFile(pathInfo);
            if (file == null)
                return null;
    
            return new VirtualFileHandler(file);
        });
    }   // eo Configure
    

回答1:

Have you had a look at the self-hosted version of RazorRockstars?

It's not the RazorFormat that needs to know about static files, they're just handled by ServiceStack itself.

You need to set the Build Action of each of the static files to Copy if newer so they're copied to the bin/ directory so ServiceStack can find them as it's the base directory where the self-hosted version of ServiceStack is hosted from.