Running Local Web Pages in CefSharp.WPF

by filip 18. January 2017 18:33

I needed to create a program which will run a web page from the local file system. Using the WebBrowser control wasn't really an option since that uses the Trident engine which didn't support many of the things we were trying to do in the web page. I went with the latest build of CefSharp.Wpf, but that doesn't natively run local files, so it had to be modified. Fortunately, I found some posts on how to enable that feature (here and here) - however, the first link was for an older version of CefSharp, and the second link only works with static resource files. I ended up merging both concepts to get it to work.

The code below works on version 53.0.1 of CefSharp.Wpf. 

First, the following two classes needed to be created:

LocalResourceHandlerFactory.cs:

using System;
using CefSharp;
namespace MyCustomNamespace
{
    public class LocalResourceHandlerFactory : IResourceHandlerFactory
    {
        public bool HasHandlers
        {
            get
            {
                return true;
            }
        }

        public IResourceHandler GetResourceHandler(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request)
        {
            return new LocalResourceHandler();
        }
    }
}

LocalResourceHandler.cs:

using System;
using System.IO;
using CefSharp;
using System.Collections.Generic;

namespace MyCustomNamespace
{
    class LocalResourceHandler : IResourceHandler
    {
        private string mimeType;
        private MemoryStream stream;

        public void Cancel()
        {

        }

        public bool CanGetCookie(Cookie cookie)
        {
            return true;
        }

        public bool CanSetCookie(Cookie cookie)
        {
            return true;
        }

        public void Dispose()
        {

        }

        public void GetResponseHeaders(IResponse response, out long responseLength, out string redirectUrl)
        {
            responseLength = stream == null ? 0 : stream.Length;
            redirectUrl = null;

            response.StatusCode = (int)System.Net.HttpStatusCode.OK;
            response.StatusText = "OK";
            response.MimeType = mimeType;
        }

        public bool ProcessRequest(IRequest request, ICallback callback)
        {
            // The 'host' portion is entirely ignored by this scheme handler.
            var uri = new Uri(request.Url);
            var file = uri.AbsolutePath;

            if (File.Exists(file))
            {
                Byte[] bytes = File.ReadAllBytes(file);
                stream = new MemoryStream(bytes);
                switch (Path.GetExtension(file))
                {
                    case ".html":
                    case ".htm":
                        mimeType = "text/html";
                        break;
                    case ".css":
                        mimeType = "text/css";
                        break;
                    case ".js":
                        mimeType = "text/javascript";
                        break;
                    case ".png":
                        mimeType = "image/png";
                        break;
                    case ".jpg":
                    case ".jpeg":
                        mimeType = "image/jpeg";
                        break;
                    case ".gif":
                        mimeType = "image/gif";
                        break;
                    case ".woff":
                        mimeType = "application/font-woff";
                        break;
                    case ".eot":
                        mimeType = "application/vnd.ms-fontobject";
                        break;
                    case ".ttf":
                        mimeType = "application/font-ttf";
                        break;
                    case ".otf":
                        mimeType = "application/font-otf";
                        break;
                    case ".svg":
                        mimeType = "image/svg+xml";
                        break;
                    case ".appcache":
                    case ".manifest":
                        mimeType = "text/cache-manifest";
                        break;
                    default:
                        mimeType = "application/octet-stream";
                        break;
                }
                callback.Continue();
                return true;
            }
            return false;
        }

        public bool ReadResponse(Stream dataOut, out int bytesRead, ICallback callback)
        {
            //Dispose the callback as it's an unmanaged resource, we don't need it in this case
            callback.Dispose();

            if (stream == null)
            {
                bytesRead = 0;
                return false;
            }

            //Data out represents an underlying buffer (typically 32kb in size).
            var buffer = new byte[dataOut.Length];
            bytesRead = stream.Read(buffer, 0, buffer.Length);

            dataOut.Write(buffer, 0, buffer.Length);

            return bytesRead > 0;
        }
    }
}

With the above code in place, we can now load the web page from a local file. The code below assumes that the HTML files are located in a 'web' subdirectory (for example, /bin/debug/web/)

public MainWindow()
        {
            
            var settings = new CefSharp.CefSettings { RemoteDebuggingPort = 1234 };
            // for some reason, performance sucks w/ the gpu enabled
            settings.CefCommandLineArgs.Add("disable-gpu", "1");
            settings.CefCommandLineArgs.Add("disable-gpu-vsync", "1");
            CefSharp.Cef.Initialize(settings);

            InitializeComponent();

            browser.ResourceHandlerFactory = new LocalResourceHandlerFactory();

            browser.BrowserSettings.FileAccessFromFileUrls = CefSharp.CefState.Enabled;
            browser.BrowserSettings.UniversalAccessFromFileUrls = CefSharp.CefState.Enabled;
            browser.BrowserSettings.WebSecurity = CefSharp.CefState.Disabled;
            //browser.BrowserSettings.WebGl = CefSharp.CefState.Disabled;



            string dir = System.IO.Directory.GetCurrentDirectory();
            String page = string.Format("{0}/web/index.html", dir);
            browser.Address = page;
        }

 

Tags: , ,

Web Development | Windows Development

Awesome Java vs .NET video

by filip 7. April 2016 17:18

I love .NET, but this video is really funny and well done.

Tags:

The jQuery Bloodforge Smoke Effect

by filip 11. June 2015 23:07

I stumbled upon a very neat piece of code written by Jonny Cornwell for a particle smoke effect. The concept was really neat, but I really wanted it to be easier to use. The end result is a jQuery plugin that allows the developer to add a particle smoke effect background to any element on the page.

The latest source files are located here:


Webkit

<div id="smoke-effect-standard" style="padding: 2em;">
   This works in webkit!
</div>
<script>
   $('#smoke-effect-standard').SmokeEffect();
</script>

This works in webkit!

The above code should work on webkit browsers (so Chrome, Safari).


Support all modern browsers

To make it work on Internet Explorer and Firefox, use the forceBackgroundRender flag. This has a much bigger performance hit (there is no performance hit on webkit since the standard render method is used), but it may be acceptable based on the size of the background.

<div id="smoke-effect-force-background" style="padding: 2em;">
   This works in all modern browsers!
</div>
<script>
   $('#smoke-effect-force-background').SmokeEffect( { forceBackgroundRender: true } );
</script>

This works in all modern browsers!

Write directly to a canvas element

Also, if you call this directly on a CANVAS tag, it will draw directly to that element.

<canvas id="smoke-effect-canvas" width="300" height="100" />
<script>
   $('#smoke-effect-canvas').SmokeEffect();
</script>


Options

  • backgroundColor: A hex or rgba value indicating the background color for the effect. If the container already has a background, the effect will inherit that. If the container does not have a background, it will be set to rgba(0, 0, 0, 0.5).
  • density: A number indicating how dense the smoke is. The higher the number, the more dense. The default is 8.
  • maximumVelocity: A number indicating how quickly the smoke travels. Default is 1
  • fps: A number indicating how often to redraw the smoke. Default is 15
  • forceBackgroundRender: If set to true, this will make the SmokeEffect work in browser that are not based on webkit. However, this comes at a performance hit. The default is false
  • image: The image to use as the smoke particle. This can be either a URL or a Base64 string of the image. You can change the color of the smoke by changing the image. If you provide a custom image, you need to update the imageWidth and imageHeight properties described below.
  • imageWidth: The width of the image for the smoke particle. Default is 128 pixels.
  • imageHeight: The height of the image for the smoke particle. Default is 128 pixels.

Example of setting all options (you don’t need to set all}.

$('selector').SmokeEffect( {
    backgroundColor: '#FF0000',
    density: 12.
    maximumVelocity: 1.5,
    fps: 20,
    forceBackgroundRender: true,
    image: 'http://myurl.com/mySmokeImage.png',
    imageWidth: 100,
    imageHeight: 150
} );

Tags:

Thermostat Statistics via Logs for Honeywell Prestige IAQ 2

by filip 21. November 2014 06:00

I created a log viewer for my Honeywell thermostat. In addition to providing a much more friendly way of viewing log files, it aggregates logs over time allowing for some pretty neat analysis.

The site is located at http://energy.bloodforge.com 

Tags:

Personal | Web Development

Updating my BlogEngine.NET blog to use SSL (HTTPS) from HTTP

by filip 28. October 2014 14:57

I’m using this post to document how I upgraded my blog for HTTPS.

The first thing I needed to do was to get a SSL certificate. I really didn’t feel like paying for one, so I went with a free certificate from StartSSL. Their free certificates expire after a year (I wish it was longer), so I’ll need to do this again next year.  But they work and… they’re free.

After I got my p12 certificate above, I asked my web host (Arvixe) to set everything up. It took them about 2 days (it was the weekend though, so maybe it would have been faster if it was during the week). This was pretty much the easiest part since all I had to do was to provide them with the cert, and they got it installed and set up the correct ports for HTTPS.

At this point, I could browse my site using HTTPS. I did have some security warnings, and to fix those I had to update my stylesheets with secure paths to my images. Also, I needed to update some script paths, as they were not secure either.

Finally, I added a rule into my web.config file so that all traffic always gets re-routed to HTTPS.

Tags:

Web Development

Bloodforge Band

Looking for the Bloodforge band site? Click here.

About Filip Stanek

Death Note Pic I'm a developer at ACG in Cincinnati, OH. I like ASP.NET, Flash, and other web technologies, & enjoy playing chess, video games, etc.

Currently playing:

Disqus

Month List