blog, github comments edit

Well, I finally did it.

For quite some time I’ve been looking at migrating my blog away from Subtext. At first I wanted to go to WordPress, but then… evaluating all the options, the blog engines, etc., I started thinking “less is more.” I originally started out using Subtext because I thought I’d want to extend the blog to do a lot of cool things. It was a great .NET blog platform and I’m a .NET guy, it was perfect.

The problem was… I didn’t do any of that.

I contributed as I could to the project, and there was a lot of great planning for the ever-impending “3.0” release, but… it just never came together. People got busy, stuff happened. Eventually, Subtext development pretty much stopped.

Part of my challenge with Subtext was the complexity of it. So many moving pieces. Database, assemblies, tons of pages and settings, skins, totally no documentation. (Well, there was some documentation that I had been writing but an unfortunate server crash lost it all.) I started looking at hosted solutions like WordPress that would be easy to use and pretty common. But, then, the challenge with any of those systems is getting your data in/out, etc. Plus, hosting costs.

So I started leaning toward a code generation sort of system. Fewer moving pieces, simpler data storage. Also, cheap. Because I’m cheap.

I decided on GitHub Pages because it’s simple, free, reliable… plus, it’s pretty well documented, Jekyll usage is simple, and Markdown is pretty sweet.

Good Stuff About GitHub Pages

  • It’s simple. Push a new post in Markdown format to your blog repo and magic happens.
  • It’s portable. All the posts are in simple text, right in the repo, so if you need to move somewhere else, it’s all right there. No database export, no huge format conversion craziness.
  • It’s free. Doesn’t get cheaper than that.
  • It’s reliable. I’m not saying 100% uptime, but putting your blog in GitHub Pages means you have the whole GitHub team watching to see if the server is down.
  • Browser editor. Create a new post right in the GitHub web interface. Nice and easy.

Less Awesome Stuff About GitHub Pages

  • There’s no server-side processing even if you need it. Ideally I’d want a 404 handler that can issue a 302 from the server-side to help people get to broken permalinks. But the 404 is just HTML generated with Jekyll, so you have to rely on JS to do the redirect. Not so awesome for search engines. I have some [really old] blog entries that were on a PHP system where the permalink is querystring-based, so I can’t even use jekyll-redirect-from to fix it.
  • The Jekyll plugins are limited. GitHub Pages has very few plugins for Jekyll that it supports. On something like OctoPress you hook up the page generation yourself so you can have whatever plugins you want… but you can’t add plugins to GitHub Pages, so the things you can do are kind of limited. (I totally understand why this is the case, doesn’t make it awesome.)
  • No post templates, painful preview. With Windows Live Writer or whatever, you didn’t have to deal with YAML front matter or any of that. The GitHub web editor interface doesn’t have an “add new post” template, so that’s a bit rough. Also, to preview your post, you have to commit the post the first time, then you have the “preview” tab you can use to see “changes” in your post. It renders Markdown nicely, but it’s sort of convoluted.
  • Drafts are weird. I may be doing this wrong, but it looks like you have to put “posts in progress” into a _drafts folder in your blog until it’s ready to go, at which point you move it to _posts.
  • Comments don’t exist. It’s not a blog host, really, so you need to use a system like Disqus for your comments. That’s not necessarily a bad thing, but it means you have some extra setup.

My Migration Process

A lot of folks who move their blog to GitHub Pages sort of “yadda yadda” away the details. “I exported my content, converted it, and imported it into GitHub Pages.” That… doesn’t help much. So I’ll give you as much detail as I can.

Standing on the Shoulders of Giants

Credit where credit is due:

Phil Haack posted a great article about how he migrated from Subtext to GitHub Pages that was super helpful. He even created a Subtext exporter that was the starting point for my data export. I, uh, liberated, a lot of code from his blog around the skin, RSS feed, and so on to get this thing going.

David Ebbo also moved to GitHub Pages and borrowed from Mr. Haack but had some enhancements I liked, like using GitHub user pages for the repository and using “tags” instead of “categories.” So I also borrowed some ideas and code from Mr. Ebbo.

If you don’t follow these blogs, go subscribe. These are some smart guys.

You Need to Know Jekyll and Liquid

You don’t have to be an expert, but it is very, very helpful to know Jekyll (the HTML content generator) and Liquid (the template engine) at least on a high-level basis. As you work through issues and fix styles or config items, this helps a lot to track things down.

Initialize the Repository

I’m using GitHub user pages for my blog, so I created a repository called tillig.github.io to host my blog. For your blog, it’d be yourusername.github.io. The article on user pages is pretty good to get you going.

Get the Infrastructure Right

Clone that repo to your local machine so you can do local dev/test to get things going. Note that if you check things in and push to the repo as you develop, you may get some emails about build failures, so local dev is good.

The GitHub page on using Jekyll tells you about how to get your local dev environment set up to run Jekyll locally.

There’s a lot to set up here, from folder structure to configuration, so the easiest way to start is to copy from someone else’s blog. This is basically what I did - I grabbed Haack’s blog, put that into my local repo, and got it running. Then I started changing the values in _config.yml to match my blog settings and fixed up the various template pieces in the _includes and _layouts folders. You can start with my blog if you like.

GOTCHA: GitHub uses pygments.rb for code syntax highlighting. If you’re developing on Windows, there’s something about pygments.rb that Windows hates. Or vice versa. Point being, for local dev on Windows, you will need to turn off syntax highlighting during local Windows dev by setting highlighter: null in your _config.yml.

I didn’t see any GitHub Pages blogs that had search on them, so I had to figure that one out myself. Luckily, Google Custom Search makes it pretty easy to get this going. Create a new “custom search engine” and set it up to search just your site. You can configure the look and feel of the search box and results page right there and it’ll give you the script to include in your site. Boom. Done.

Fix Up RSS

The Octopress-based RSS feed uses a custom plugin expand_urls to convert relative URLs like /about.html into absolute URLs like http://yoursite.com/about.html That no worky in GitHub Pages, so you have to use a manual replace filter on URLs in the RSS feed. (If you look at my atom.xml file you can see this in action.)

Make Last Minute Fixes to Existing Content

I found that it was easier to do any last-minute fixes in my existing blog content rather than doing it post-export. For example, I was hosting my images in ImageShack for a long time, but the reliability of ImageShack (even with a paid account) is total crap. I lost so many images… argh. So I went through a process of moving all of my images to OneDrive and it was easier to do that in my original blog so I could make sure the links were properly updated.

If you have anything like that, do it before export.

Export Your Content and Comments

This was the trickiest part, at least for me.

Haack was running on his own server and had direct database access to his content so a little SQL and he was done. I was on a shared server without any real SQL Management Console access or remote access to run SQL against my database, so I had to adjust my export mechanism to be more of a two-phase thing: Get the data out of my database using an .aspx page that executed in the context of the blog, then take the exported content and transform that into blog posts.

There also wasn’t anything in Haack’s setup to handle the comment export for use in Disqus, so I had to do that, too.

Oh, and Haack was on some newer/custom version of Subtext where the database schema was different from mine, so I had to fix that to work with Subtext 2.5.2.0.

Here’s my forked version of Haack’s subtext-jekyll-exporter that you can use for exporting your content and comments. You can also fork it as a starter for your own export process.

  • Drop the JekyllExport.aspx and DisqusCommentExport.aspx files into your Subtext blog.
  • Save the output of each as an XML file.
  • Make your URLs relative. I have a little section on this just below, but it’s way easier to deal with local blog development if your URLs don’t have the protocol or host info in them for internal links. It’s easier to do this in the exported content before running the exporter to process into Markdown.
  • Run the SubtextJekyllExporter.exe on the XML from JekyllExport.aspx to convert it into Markdown. These will be the Markdown pages that go in the _posts/archived folder and they’ll have Disqus identifiers ready to go to tie existing comments to the articles.
  • In Disqus, import a “general” WXR file and use the XML from DisqusCommentExport.aspx as the WXR file. It may take a while to import, so give it some time.

You can test this out locally when it’s done. Using Jekyll to host your site locally, check out your comment section on one of the posts in your site with comments. They should show up.

Make URLs Relative

It is way easier to test your blog locally if the links work. That means if you have absolute links like http://yoursite.com/link/target.html they’re going to only work if the link is truly live. If, however, you have /link/target.html then it’ll work on your local test machine, it’ll work from yourusername.github.io, and it’ll work from your final blog site.

I did a crude replacement on my blog entries that seemed to work pretty well.

Replace ="http://www.mysite.com/" with ="/" and that seemed to be enough (using my domain name in there, of course). YMMV on that one.

Push It

Once everything looks good locally, push it to your public repo. (If you’re on Windows, don’t forget to comment out that highlighter: null in _config.yml.) Give it a few minutes and you should be able to see your blog at http://yourusername.github.io - navigate around and do any further fix-up.

Configure DNS

This was a finicky thing for me. I don’t mess with DNS much so it took me a bit to get this just right.

My blog is at www.paraesthesia.com (I like the www part, some folks don’t). GitHub has some good info about setting up your custom domain but it was still a little bit confusing and “spread out” for me.

For the www case, like mine:

What got me/wasn’t clear was that for the www special case, you have to do both the A and CNAME records.

Once you do that, yourdomain.com and www.yourdomain.com will both make it to your blog. (If you don’t like the www part, make your CNAME file in your repo only contain yourdomain.com instead of www.yourdomain.com.)

Remaining Items

I still have a few things to fix up, but for the most part I’m moved over.

There are still some quirky CSS things I need to fix that I’m not happy with. Looking at the headers in this entry, for example, they have some crazy overlapping with the first line under them.

I have some in-page JS demos that were sort of challenging to set up in Subtext but should be easier in the new setup. I need to move those over; right now they’re broken.

I also have the “Command Prompt Here Generator” app that was running on my blog site but is now inaccessible because I have to get it going on a site with dynamic abilities. I’ll probably use my old blog host site as an “app host” now where I just put little dynamic apps. It’ll be easier to do that stuff without Subtext right in the root of the site.

I’ll get there, but for now… I’m feeling pretty good.

net comments edit

One of the most frequent StackOverflow questions we see for Autofac involves some confusion over how to deal with components in applications like MVC and Web API that support per-request dependencies.

To help folks out, I wrote up a fairly comprehensive document on the Autofac doc site addressing the various questions around per-request dependencies.

We’re still working on porting over the wiki content into the doc site. While that is going on, things are a little “split” between the two sites. If the content is on the doc site, go for that over the wiki. The doc site has content that’s a little more robust and detailed than the wiki had (which is part of the desire to move to the doc site).

net comments edit

Over at Autofac we’re trying to get a more robust set of documentation out to help folks. The wiki is nice, but it leaves a lot to be desired.

As part of that, we’re also trying to get some answers published to some of the more frequently asked questions we see popping up on StackOverflow.

Today I pushed out the doc answering that timeless question, “How do I pick a service implementation based on a particular context or consuming object?”

media comments edit

I’ve been ripping a lot of SD video lately, converting my full-disc VIDEO_TS folder images to .m4v files for use with Plex, and I’ve learned quite a bit about what I like (or don’t) and things I have to look for in the final conversion. Surprisingly enough, default settings never seem to work quite right for me.

The settings I use are some minor changes to the “High Profile” default. I’ll note the differences.

Updated 1/2/2015 for 0.10.0 Handbrake release.

Picture

  • Width/Height: nil (let it auto-correct)
  • Anamorphic: Loose
  • Modulus: 2
  • Cropping: Automatic

Filters

  • Detelecine: Off
  • Decomb: Default
  • Deinterlace: Off
  • Denoise: Off
  • Deblock: Off
  • Grayscale: Unchecked

Video

  • Video Codec: H.264 (x.264)
  • Framerate FPS: Same as source
  • Constant Framerate (this is different than High Profile)
  • x264 Preset: Slower
  • x264 Tune: Film, Animation, or Grain (depends on the source – I change this per item ripped; this is different than High Profile)
  • H.264 Profile: High
  • H.264 Level: 4.1
  • Fast Decode: Unchecked
  • Extra Options: Empty
  • Quality: Constant Quality 18 (this is different than High Profile)

Audio

Track 1:

  • Source: The best AC3 sound track on there with the most channels. (It usually does a good job of auto-detecting.)
  • Codec: AAC (FDK) (this is different than High Profile)
  • Bitrate: 256 (this is different than High Profile)
  • Samplerate: Auto
  • Mixdown: Dolby Pro Logic II
  • DRC: 0.0
  • Gain: 0

Track 2:

  • Source: Same as Track 1.
  • Codec: AC3 Passthru

Track 3 (depending on source)

  • Source: The DTS track, if there is one.
  • Codec: DTS Passthru

Subtitles: Generally none, but there are some movies that need them, in which case I’ll add one track. High Profile (and my settings) generally don’t include this.

  • Source: English (VobSub)
  • Forced Only: Unchecked
  • Burn In: Checked
  • Default: Unchecked
  • Everything else default.

Chapters: I do select “Create chapter markers” but I let the automatic detection do the naming and timing.

This seems to give me the best bang for my buck. I tried with lower quality settings and such, but it never quite got where I wanted it. With these settings, I generally can’t tell the difference between the original source and the compressed version.

I’ve found that I have to check for a few things to see if something needs to be tweaked or re-ripped.

  • Cropping: About 80% of the time, Handbrake does an awesome job cropping the letterbox off and cleaning up the sides. That other 20%, you get this odd floating black bar on one or more of the sides where the picture wasn’t cropped right. This is much easier to catch if you always use the “Preview” button on the “Picture” tab. You can scan through the video and adjust the manual crop settings easily.
  • Film grain: By default I try the “Film” x264 Tune setting for most movies unless I’m sure there’s a grain or high level of detail to it. Nevertheless, sometimes I’ll come across a film where dark spots have the background appear as though it’s “moving” – like a thousand little grains of sand vibrating. If I see that, I re-rip and switch to the “Grain” x264 Tune setting and that fixes it right up. I also sometimes see a film that looks like all the definition was lost and things are blocky – in this case, I’ll also switch to “Grain.”
  • Lip sync: I started out using the default “Variable Framerate” setting on the Video tab. I’m now in the process of re-ripping like a quarter of my movies because I didn’t stop to see if the lips were synchronized with the words in the soundtrack. By switching to “Constant Framerate,” everything syncs up and looks right. I’ve since switched my default setting to Constant Framerate.

Making new presets is more reliable if you modify the XML settings directly. Your presets file is located in your user application data folder, like C:\Users\Travis\AppData\Roaming\HandBrake\user_presets.xml. I found that if you modify an existing preset and then save a new preset based on that, it’s totally affected by whether or not you have a file loaded to rip, what sorts of audio tracks are there, and so on. If you want a good preset, it’s best to select the preset you want to modify, make the changes, and then use a diff program to compare the built-in setting XML to the user setting XML file. It’s pretty easy to tell what you changed (the XML is easy to read), so just copy the built-in setting and update the XML with your specific changes.

Here’s my current user_presets.xml file:

<?xml version="1.0"?>
<ArrayOfPreset xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Preset>
    <Category>User Presets</Category>
    <Description />
    <IsBuildIn>false</IsBuildIn>
    <IsDefault>true</IsDefault>
    <Name>Illig High Profile - SD Film</Name>
    <PictureSettingsMode>Custom</PictureSettingsMode>
    <UseDeinterlace>false</UseDeinterlace>
    <Task>
      <Title>0</Title>
      <Angle>0</Angle>
      <PointToPointMode>Chapters</PointToPointMode>
      <StartPoint>0</StartPoint>
      <EndPoint>0</EndPoint>
      <OutputFormat>Mp4</OutputFormat>
      <OptimizeMP4>false</OptimizeMP4>
      <IPod5GSupport>false</IPod5GSupport>
      <Width xsi:nil="true" />
      <Height xsi:nil="true" />
      <MaxWidth xsi:nil="true" />
      <MaxHeight xsi:nil="true" />
      <Cropping>
        <Top>0</Top>
        <Bottom>0</Bottom>
        <Left>0</Left>
        <Right>0</Right>
      </Cropping>
      <HasCropping>false</HasCropping>
      <Anamorphic>Loose</Anamorphic>
      <DisplayWidth xsi:nil="true" />
      <KeepDisplayAspect>false</KeepDisplayAspect>
      <PixelAspectX>0</PixelAspectX>
      <PixelAspectY>0</PixelAspectY>
      <Modulus>2</Modulus>
      <Deinterlace>Off</Deinterlace>
      <Decomb>Default</Decomb>
      <Detelecine>Off</Detelecine>
      <Denoise>Off</Denoise>
      <DenoisePreset>Weak</DenoisePreset>
      <DenoiseTune>None</DenoiseTune>
      <Deblock>0</Deblock>
      <Grayscale>false</Grayscale>
      <VideoEncodeRateType>ConstantQuality</VideoEncodeRateType>
      <VideoEncoder>X264</VideoEncoder>
      <FramerateMode>CFR</FramerateMode>
      <Quality>18</Quality>
      <VideoBitrate xsi:nil="true" />
      <TwoPass>false</TwoPass>
      <TurboFirstPass>false</TurboFirstPass>
      <Framerate xsi:nil="true" />
      <AudioTracks>
        <AudioTrack>
          <Bitrate>256</Bitrate>
          <DRC>0</DRC>
          <IsDefault>false</IsDefault>
          <Encoder>fdkaac</Encoder>
          <Gain>0</Gain>
          <MixDown>DolbyProLogicII</MixDown>
          <SampleRate>0</SampleRate>
          <SampleRateDisplayValue>Auto</SampleRateDisplayValue>
          <ScannedTrack>
            <TrackNumber>0</TrackNumber>
            <SampleRate>0</SampleRate>
            <Bitrate>0</Bitrate>
          </ScannedTrack>
          <TrackName />
        </AudioTrack>
        <AudioTrack>
          <Bitrate>256</Bitrate>
          <DRC>0</DRC>
          <IsDefault>false</IsDefault>
          <Encoder>Ac3Passthrough</Encoder>
          <Gain>0</Gain>
          <MixDown>Auto</MixDown>
          <SampleRate>0</SampleRate>
          <SampleRateDisplayValue>Auto</SampleRateDisplayValue>
          <ScannedTrack>
            <TrackNumber>0</TrackNumber>
            <SampleRate>0</SampleRate>
            <Bitrate>0</Bitrate>
          </ScannedTrack>
          <TrackName />
        </AudioTrack>
      </AudioTracks>
      <AllowedPassthruOptions>
        <AudioAllowAACPass>true</AudioAllowAACPass>
        <AudioAllowAC3Pass>true</AudioAllowAC3Pass>
        <AudioAllowDTSHDPass>true</AudioAllowDTSHDPass>
        <AudioAllowDTSPass>true</AudioAllowDTSPass>
        <AudioAllowMP3Pass>true</AudioAllowMP3Pass>
        <AudioEncoderFallback>Ac3</AudioEncoderFallback>
      </AllowedPassthruOptions>
      <SubtitleTracks />
      <IncludeChapterMarkers>true</IncludeChapterMarkers>
      <ChapterNames />
      <X264Preset>Slower</X264Preset>
      <QsvPreset>Quality</QsvPreset>
      <H264Profile>High</H264Profile>
      <H264Level>4.1</H264Level>
      <X264Tune>Film</X264Tune>
      <FastDecode>false</FastDecode>
      <X265Preset>VeryFast</X265Preset>
      <H265Profile>Main</H265Profile>
      <X265Tune>None</X265Tune>
      <PreviewStartAt xsi:nil="true" />
      <PreviewDuration xsi:nil="true" />
      <IsPreviewEncode>false</IsPreviewEncode>
      <PreviewEncodeDuration>0</PreviewEncodeDuration>
      <ShowAdvancedTab>false</ShowAdvancedTab>
    </Task>
    <UsePictureFilters>true</UsePictureFilters>
  </Preset>
  <Preset>
    <Category>User Presets</Category>
    <Description />
    <IsBuildIn>false</IsBuildIn>
    <IsDefault>false</IsDefault>
    <Name>Illig High Profile - SD 2D Anim</Name>
    <PictureSettingsMode>Custom</PictureSettingsMode>
    <UseDeinterlace>false</UseDeinterlace>
    <Task>
      <Title>0</Title>
      <Angle>0</Angle>
      <PointToPointMode>Chapters</PointToPointMode>
      <StartPoint>0</StartPoint>
      <EndPoint>0</EndPoint>
      <OutputFormat>Mp4</OutputFormat>
      <OptimizeMP4>false</OptimizeMP4>
      <IPod5GSupport>false</IPod5GSupport>
      <Width xsi:nil="true" />
      <Height xsi:nil="true" />
      <MaxWidth xsi:nil="true" />
      <MaxHeight xsi:nil="true" />
      <Cropping>
        <Top>0</Top>
        <Bottom>0</Bottom>
        <Left>0</Left>
        <Right>0</Right>
      </Cropping>
      <HasCropping>false</HasCropping>
      <Anamorphic>Loose</Anamorphic>
      <DisplayWidth xsi:nil="true" />
      <KeepDisplayAspect>false</KeepDisplayAspect>
      <PixelAspectX>0</PixelAspectX>
      <PixelAspectY>0</PixelAspectY>
      <Modulus>2</Modulus>
      <Deinterlace>Off</Deinterlace>
      <Decomb>Default</Decomb>
      <Detelecine>Off</Detelecine>
      <Denoise>Off</Denoise>
      <DenoisePreset>Weak</DenoisePreset>
      <DenoiseTune>None</DenoiseTune>
      <Deblock>0</Deblock>
      <Grayscale>false</Grayscale>
      <VideoEncodeRateType>ConstantQuality</VideoEncodeRateType>
      <VideoEncoder>X264</VideoEncoder>
      <FramerateMode>CFR</FramerateMode>
      <Quality>18</Quality>
      <VideoBitrate xsi:nil="true" />
      <TwoPass>false</TwoPass>
      <TurboFirstPass>false</TurboFirstPass>
      <Framerate xsi:nil="true" />
      <AudioTracks>
        <AudioTrack>
          <Bitrate>256</Bitrate>
          <DRC>0</DRC>
          <IsDefault>false</IsDefault>
          <Encoder>fdkaac</Encoder>
          <Gain>0</Gain>
          <MixDown>DolbyProLogicII</MixDown>
          <SampleRate>0</SampleRate>
          <SampleRateDisplayValue>Auto</SampleRateDisplayValue>
          <ScannedTrack>
            <TrackNumber>0</TrackNumber>
            <SampleRate>0</SampleRate>
            <Bitrate>0</Bitrate>
          </ScannedTrack>
          <TrackName />
        </AudioTrack>
        <AudioTrack>
          <Bitrate>256</Bitrate>
          <DRC>0</DRC>
          <IsDefault>false</IsDefault>
          <Encoder>Ac3Passthrough</Encoder>
          <Gain>0</Gain>
          <MixDown>Auto</MixDown>
          <SampleRate>0</SampleRate>
          <SampleRateDisplayValue>Auto</SampleRateDisplayValue>
          <ScannedTrack>
            <TrackNumber>0</TrackNumber>
            <SampleRate>0</SampleRate>
            <Bitrate>0</Bitrate>
          </ScannedTrack>
          <TrackName />
        </AudioTrack>
      </AudioTracks>
      <AllowedPassthruOptions>
        <AudioAllowAACPass>true</AudioAllowAACPass>
        <AudioAllowAC3Pass>true</AudioAllowAC3Pass>
        <AudioAllowDTSHDPass>true</AudioAllowDTSHDPass>
        <AudioAllowDTSPass>true</AudioAllowDTSPass>
        <AudioAllowMP3Pass>true</AudioAllowMP3Pass>
        <AudioEncoderFallback>Ac3</AudioEncoderFallback>
      </AllowedPassthruOptions>
      <SubtitleTracks />
      <IncludeChapterMarkers>true</IncludeChapterMarkers>
      <ChapterNames />
      <X264Preset>Slower</X264Preset>
      <QsvPreset>Quality</QsvPreset>
      <H264Profile>High</H264Profile>
      <H264Level>4.1</H264Level>
      <X264Tune>Animation</X264Tune>
      <FastDecode>false</FastDecode>
      <X265Preset>VeryFast</X265Preset>
      <H265Profile>Main</H265Profile>
      <X265Tune>None</X265Tune>
      <PreviewStartAt xsi:nil="true" />
      <PreviewDuration xsi:nil="true" />
      <IsPreviewEncode>false</IsPreviewEncode>
      <PreviewEncodeDuration>0</PreviewEncodeDuration>
      <ShowAdvancedTab>false</ShowAdvancedTab>
    </Task>
    <UsePictureFilters>true</UsePictureFilters>
  </Preset>
  <Preset>
    <Category>User Presets</Category>
    <Description />
    <IsBuildIn>false</IsBuildIn>
    <IsDefault>false</IsDefault>
    <Name>Illig High Profile - SD Grain</Name>
    <PictureSettingsMode>Custom</PictureSettingsMode>
    <UseDeinterlace>false</UseDeinterlace>
    <Task>
      <Title>0</Title>
      <Angle>0</Angle>
      <PointToPointMode>Chapters</PointToPointMode>
      <StartPoint>0</StartPoint>
      <EndPoint>0</EndPoint>
      <OutputFormat>Mp4</OutputFormat>
      <OptimizeMP4>false</OptimizeMP4>
      <IPod5GSupport>false</IPod5GSupport>
      <Width xsi:nil="true" />
      <Height xsi:nil="true" />
      <MaxWidth xsi:nil="true" />
      <MaxHeight xsi:nil="true" />
      <Cropping>
        <Top>0</Top>
        <Bottom>0</Bottom>
        <Left>0</Left>
        <Right>0</Right>
      </Cropping>
      <HasCropping>false</HasCropping>
      <Anamorphic>Loose</Anamorphic>
      <DisplayWidth xsi:nil="true" />
      <KeepDisplayAspect>false</KeepDisplayAspect>
      <PixelAspectX>0</PixelAspectX>
      <PixelAspectY>0</PixelAspectY>
      <Modulus>2</Modulus>
      <Deinterlace>Off</Deinterlace>
      <Decomb>Default</Decomb>
      <Detelecine>Off</Detelecine>
      <Denoise>Off</Denoise>
      <DenoisePreset>Weak</DenoisePreset>
      <DenoiseTune>None</DenoiseTune>
      <Deblock>0</Deblock>
      <Grayscale>false</Grayscale>
      <VideoEncodeRateType>ConstantQuality</VideoEncodeRateType>
      <VideoEncoder>X264</VideoEncoder>
      <FramerateMode>CFR</FramerateMode>
      <Quality>18</Quality>
      <VideoBitrate xsi:nil="true" />
      <TwoPass>false</TwoPass>
      <TurboFirstPass>false</TurboFirstPass>
      <Framerate xsi:nil="true" />
      <AudioTracks>
        <AudioTrack>
          <Bitrate>256</Bitrate>
          <DRC>0</DRC>
          <IsDefault>false</IsDefault>
          <Encoder>fdkaac</Encoder>
          <Gain>0</Gain>
          <MixDown>DolbyProLogicII</MixDown>
          <SampleRate>0</SampleRate>
          <SampleRateDisplayValue>Auto</SampleRateDisplayValue>
          <ScannedTrack>
            <TrackNumber>0</TrackNumber>
            <SampleRate>0</SampleRate>
            <Bitrate>0</Bitrate>
          </ScannedTrack>
          <TrackName />
        </AudioTrack>
        <AudioTrack>
          <Bitrate>256</Bitrate>
          <DRC>0</DRC>
          <IsDefault>false</IsDefault>
          <Encoder>Ac3Passthrough</Encoder>
          <Gain>0</Gain>
          <MixDown>Auto</MixDown>
          <SampleRate>0</SampleRate>
          <SampleRateDisplayValue>Auto</SampleRateDisplayValue>
          <ScannedTrack>
            <TrackNumber>0</TrackNumber>
            <SampleRate>0</SampleRate>
            <Bitrate>0</Bitrate>
          </ScannedTrack>
          <TrackName />
        </AudioTrack>
      </AudioTracks>
      <AllowedPassthruOptions>
        <AudioAllowAACPass>true</AudioAllowAACPass>
        <AudioAllowAC3Pass>true</AudioAllowAC3Pass>
        <AudioAllowDTSHDPass>true</AudioAllowDTSHDPass>
        <AudioAllowDTSPass>true</AudioAllowDTSPass>
        <AudioAllowMP3Pass>true</AudioAllowMP3Pass>
        <AudioEncoderFallback>Ac3</AudioEncoderFallback>
      </AllowedPassthruOptions>
      <SubtitleTracks />
      <IncludeChapterMarkers>true</IncludeChapterMarkers>
      <ChapterNames />
      <X264Preset>Slower</X264Preset>
      <QsvPreset>Quality</QsvPreset>
      <H264Profile>High</H264Profile>
      <H264Level>4.1</H264Level>
      <X264Tune>Grain</X264Tune>
      <FastDecode>false</FastDecode>
      <X265Preset>VeryFast</X265Preset>
      <H265Profile>Main</H265Profile>
      <X265Tune>None</X265Tune>
      <PreviewStartAt xsi:nil="true" />
      <PreviewDuration xsi:nil="true" />
      <IsPreviewEncode>false</IsPreviewEncode>
      <PreviewEncodeDuration>0</PreviewEncodeDuration>
      <ShowAdvancedTab>false</ShowAdvancedTab>
    </Task>
    <UsePictureFilters>true</UsePictureFilters>
  </Preset>
</ArrayOfPreset>

net, aspnet comments edit

In working with a REST API project I’m on, I was tasked to create a DELETE operation that would take the resource ID in the URL path, like:

DELETE /api/someresource/reallylongresourceidhere HTTP/1.1

The resource ID we had was really, really long base-64 encoded value. About 750 characters long. No, don’t bug me about why that was the case, just… stick with me. I had to get it to work in IIS and OWIN hosting.

STOP. STOP RIGHT HERE. I’m going to tell you some ways to tweak URL request validation. This is a security thing. Security is Good. IN THE END, I DIDN’T DO THESE. I AM NOT RECOMMEDING YOU DO THEM. But, you know, if you run into one of the issues I ran into… here are some ways you can work around it at your own risk.

Problem 1: The Overall URL Length

By default, ASP.NET has a max URL length set at 260 characters. Luckily, you can change that in web.config:

<configuration>
  <system.web>
    <httpRuntime maxUrlLength="2048" />
  </system.web>
</configuration>

Setting that maxUrlLength value got me past the first hurdle.

Problem 2: URL Decoding

Base 64 includes the “/” character – the path slash. Even if you encode it on the URL like this…

/api/someresource/abc%2Fdef%2fghi

…when .NET reads it, it gets entirely decoded:

/api/someresource/abc/def/ghi

…which then, of course, got me a 404 Not Found because my route wasn’t set up like that.

This is also something you can control through web.config:

<configuration>
  <uri>
    <schemeSettings>
      <add name="http" genericUriParserOptions="DontUnescapePathDotsAndSlashes" />
      <add name="https" genericUriParserOptions="DontUnescapePathDotsAndSlashes" />
    </schemeSettings>
  </uri>
</configuration>

Now that the URL is allowed through and it’s not being proactively decoded (so I can get routing working), the last hurdle is…

Problem 3: Max Path Segment Length

The key, if you recall, is about 750 characters long. I can have a URL come through that’s 2048 characters long, but there’s still validation on each path segment length.

The tweak for this is in the registry. Find the registry key HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\HTTP\Parameters and add a DWORD value UrlSegmentMaxLength with the value of the max segment length. The default is 260; I had to update mine to 1024.

After you change that value, you have to reboot to get it to take effect.

This is the part that truly frustrated me. Even running in the standalone OWIN host, this value is still used. I thought OWIN and OWIN hosting was getting us away from IIS, but the low-level http.sys is still being used in there somewhere. I guess I just didn’t realize that and maybe I should have. I mean, .NET is all just wrappers on unmanaged crap anyway, right? :)

WHAT I ENDED UP DOING

Having to do all that to get this working set me on edge. I don’t mind increasing, say, the max URL length, but I had to tweak a lot, and that left me with a bad taste in my mouth. Deployment pain, potential security pain… not worth it.

Since we had control over how the resource IDs were generated in the first place, I changed the algorithm so we could fit them all under 260 characters – the max path segment length. I left the overall URL length configuration in web.config at a higher number, but shrunk it down to 1024 instead of sticking at 2048. I ditched the registry change – no longer needed.