I was a little bored and felt like porting mynyml’s unindent gem to C# as an extension method on String:
And here’s mynyml’s original Ruby code:
I was a little bored and felt like porting mynyml’s unindent gem to C# as an extension method on String:
And here’s mynyml’s original Ruby code:
http://blog.objectmentor.com/articles/2010/04/14/c-tdd-videos-you-asked-for-them
http://www.iamnotmyself.com/2009/10/23/TDDKataCalculatorDemonstration.aspx
http://osherove.com/tdd-kata-1/
http://katas.softwarecraftsmanship.org/
http://rickardnilsson.net/post/2010/07/21/Prime-Factors-Kata.aspx
Delicious.
Jul 19
Posted by Charles in Uncategorized | 2 Comments
So here’s the thing – we all hate having to tie our Visual Studio solutions to an IIS web site when the ASP.NET Development Server will do just fine. Sure, it’s best to test our web apps on a live, flesh and blood IIS server – but for small scale projects, why bother? You and I are happy to use it 99% of the time…
… but some times we can’t!
That’s right – ASP.NET Development Server refuses remote connections. What’s an iPhone web app developer to do? Use IIS so I can establish remote connections from my iPhone?
Hell no!
Ohhhh yeah! It’s time to bring out the big guns. We’re gonna have us a little hackin’ action. If the dev server doesn’t want to play nice, we’ll make it!
Step 1: Let’s grab the dev server executable. You can find out where it’s located by debugging a ASP.NET web project, opening the Task Manager and clicking the “Open File Location” on the WebDev.WebServer.EXE. Copy that file to c:\temp, where we’ll do a little patch work later on. In my case, it’s in the following folder: C:\Program Files (x86)\Common Files\microsoft shared\DevServer\10.0
Step 2: It’s time to perform open heart surgery. Grab Reflector, and let’s get to work. Drag and drop the executable onto Reflector and take a look around. You’ll notice that there’s nothing of real interest here – it delegates most of the heavy lifting to the WebDev.WebHost40 assembly. Let’s figure out where that is like so:
Now that we know where it is, let’s copy that to c:\temp:
xcopy C:\Windows\Microsoft.Net\assembly\GAC_32\WebDev.WebHost40\v4.0_10.0.0.0__b03f5f7f11d50a3a\WebDev.WebHost40.dll c:\temp
Step 3: Back to Reflector! Let’s take a look around for a sec… Did you notice the Request class? Let’s take a look there. Ah! Request.Process() looks rather suspicious:
[AspNetHostingPermission(SecurityAction.Assert, Level=AspNetHostingPermissionLevel.Medium)]
public void Process()
{
if (this.TryParseRequest())
{
if (((this._verb == "POST") && (this._contentLength > 0)) && (this._preloadedContentLength < this._contentLength))
{
this._connection.Write100Continue();
}
if (!this._host.RequireAuthentication || this.TryNtlmAuthenticate())
{
if (this._isClientScriptPath)
{
this._connection.WriteEntireResponseFromFile(this._host.PhysicalClientScriptPath + this._path.Substring(this._host.NormalizedClientScriptPath.Length), false);
}
else if (this.IsRequestForRestrictedDirectory())
{
this._connection.WriteErrorAndClose(0x193);
}
else if (!this.ProcessDefaultDocumentRequest())
{
this.PrepareResponse();
HttpRuntime.ProcessRequest(this);
}
}
}
}
Hmmm… that call to TryParseRequest()… let’s take a look:
private bool TryParseRequest()
{
this.Reset();
this.ReadAllHeaders();
if (!this._connection.IsLocal)
{
this._connection.WriteErrorAndClose(0x193);
return false;
}
if (((this._headerBytes == null) || (this._endHeadersOffset < 0)) || ((this._headerByteStrings == null) || (this._headerByteStrings.Count == 0)))
{
this._connection.WriteErrorAndClose(400);
return false;
}
this.ParseRequestLine();
if (this.IsBadPath())
{
this._connection.WriteErrorAndClose(400);
return false;
}
if (!this._host.IsVirtualPathInApp(this._path, out this._isClientScriptPath))
{
this._connection.WriteErrorAndClose(0x194);
return false;
}
this.ParseHeaders();
this.ParsePostedContent();
return true;
}
Busted! If the connection is not local, return a 403 and close the connection – WriteErrorAndClose(0×193). Let’s put this on our naughty list – we’ll get back to it later on.
Step 4: Hunt down the Loopbacks! Here’s Server.Start():
public void Start()
{
try
{
this._socket = this.CreateSocketBindAndListen(AddressFamily.InterNetwork, IPAddress.Loopback, this._port);
}
catch (Exception exception)
{
SocketException exception2 = exception as SocketException;
if ((exception2 != null) && (exception2.SocketErrorCode == SocketError.AddressAlreadyInUse))
{
throw exception;
}
this._socket = this.CreateSocketBindAndListen(AddressFamily.InterNetworkV6, IPAddress.IPv6Loopback, this._port);
}
if (this._socket != null)
{
ThreadPool.QueueUserWorkItem(this._onStart);
}
}
Those Loopbacks gotta go.
Step 5: It’s surgery time. Use ILDASM to dump WebDev.WebServer.EXE and WebDev.WebHost40.dll to c:\temp\server\WebDev.WebServer.IL and c:\temp\host\WebDev.WebHost40.IL, respectively. When prompted, tick each checkbox on the output options.
Let’s start with the host. Open up WebDev.WebHost40.IL, preferably with a real text editor. Let’s first find those Loopbacks – locate the Server.Start() method:
.method /*0600009B*/ public hidebysig instance void
Start() cil managed
// SIG: 20 00 01
{
Now, replace Loopback and IPV6Loopback with Any and IPV6Any, respectively. In other words, this:
IL_0003: /* 7E | (0A)0000A4 */ ldsfld class [System/*23000003*/]System.Net.IPAddress/*01000015*/ [System/*23000003*/]System.Net.IPAddress/*01000015*/::Loopback /* 0A0000A4 */
becomes:
IL_0003: /* 7E | (0A)0000A4 */ ldsfld class [System/*23000003*/]System.Net.IPAddress/*01000015*/ [System/*23000003*/]System.Net.IPAddress/*01000015*/::Any /* 0A0000A4 */
Great! Now it’ll accept connections – but it will still respond with a 403 and drop the connection – no bueno! Let’s fix it.
Here’s the offending code:
if (!this._connection.IsLocal)
{
this._connection.WriteErrorAndClose(0x193);
return false;
}
That translates to the following IL (from the TryParseRequest() method):
// if (this._connection.IsLocal) goto IL_002b
IL_000c: /* 02 | */ ldarg.0
IL_000d: /* 7B | (04)00004E */ ldfld class Microsoft.VisualStudio.WebHost.Connection/*02000004*/ Microsoft.VisualStudio.WebHost.Request/*0200000B*/::_connection /* 0400004E */
IL_0012: /* 6F | (06)000015 */ callvirt instance bool Microsoft.VisualStudio.WebHost.Connection/*02000004*/::get_IsLocal() /* 06000015 */
IL_0017: /* 2D | 12 */ brtrue.s IL_002b
// this._connection.WriteErrorAndClose(403); return;
IL_0019: /* 02 | */ ldarg.0
IL_001a: /* 7B | (04)00004E */ ldfld class Microsoft.VisualStudio.WebHost.Connection/*02000004*/ Microsoft.VisualStudio.WebHost.Request/*0200000B*/::_connection /* 0400004E */
IL_001f: /* 20 | 93010000 */ ldc.i4 0x193
IL_0024: /* 6F | (06)000023 */ callvirt instance void Microsoft.VisualStudio.WebHost.Connection/*02000004*/::WriteErrorAndClose(int32) /* 06000023 */
IL_0029: /* 16 | */ ldc.i4.0
IL_002a: /* 2A | */ ret
// blah blah blah . . .
Pretty simple, right? If the connection is local, branch – go to IL_002b and continue processing. There’s several ways you can fix this – my suggestion is that you just replace the “this._connection.WriteErrorAndClose(403)” code with NOPs. Here’s what you end up with:
IL_0019: nop
IL_001a: nop
IL_001b: nop
IL_001c: nop
IL_001d: nop
IL_001e: nop
IL_001f: nop
IL_0020: nop
IL_0021: nop
IL_0022: nop
IL_0023: nop
IL_0024: nop
IL_0025: nop
IL_0026: nop
IL_0027: nop
IL_0028: nop
IL_0029: nop
IL_002a: nop
Yay! One last little change:
.assembly /*20000001*/ WebDev.WebHost40
{
// blah blah blah
.ver 10:0:0:0 // Let's bump this up to .ver 10:1:0:0
}
Now, create a strong name key using Sn.exe. After you have your snk, compile the IL using:
ilasm /dll /resource=webdev.webhost40.res /key=c:\temp\mykey.snk webdev.webhost40.il
Install the assembly into the GAC:
gacutil /i c:\temp\webdev.webhost.dll
One assembly down, one more to go; we still need to update the web server’s reference to the new WebDev.WebHost40. Open up WebDev.WebServer40.IL and change this:
.assembly extern /*23000005*/ WebDev.WebHost40
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A )
.ver 10:0:0:0
}
to
.assembly extern /*23000005*/ WebDev.WebHost40
{
.publickeytoken = (00 00 00 00 00 00 00 00 ) // put _YOUR_ public key here!!!
.ver 10:1:0:0
}
Now it’s time to compile using ilasm: ilasm /exe /resource=WebDev.WebServer40.res /key=c:\temp\mykey.snk WebDev.WebServer40.il
Give it a test:
c:\temp\server\WebDev.WebServer40.exe /port:1234 /path:c:\path\to\website /vpath:website [/ntlm]
You’re golden, Ponyboy! Create a backup folder in your DevServer\10.0 folder, then feel free to replace the original executable with your patched version.
Thanks go to Alex Gosh for the following code snippet – I wouldn’t have figured this out without his blog post:
The ResourceInspector class provides an easy way to inspect the Resources within your Silverlight assemblies. The inspect method returns an IDictionary where each key/value pair consists of the resource name and the appropriate uri. If you combine this with Jason Cooke’s WebXapFileLoader and XapInspector, you’ll be able to enumerate all “Content” and “Resource” files at runtime.
The nice thing about this discovery is that I’ll be able to create a custom Platform Adaption Layer with additional features. The current BrowserPAL is limited to providing a Stream instance when given a known “Content” file name – it does not support “Resource” files from arbitrary assemblies, and you can’t enumerate the files within the virtual file system. As a result, the following IronRuby code will throw a “NotImplementedException”:
Dir.glob ‘.’
However, it’s possible to implement a custom PAL (using the code snippet above) that would allow DLR languages to enumerate the files contained within the XAP and assemblies. I’ll try to whip up a proof of concept soon and post it here.
Cheers,
-Charles
In this post I’ll show you some tips when working with IronRuby in Silverlight. While you can use almost identical code whether you’re working on the desktop or within the browser, you’ll have to make a few tweaks if you want to do any file operations from Ruby (ex: File.open ‘some_image.png’, require ‘foo’, etc). Make sure that you set the “Build Action” to “Content” for each script and/or resource in your project.
The DLR provides an abstraction over platform functionality using PlatformAdaptionLayers (PALs). In order to read from your XAP’s contents you’ll need to use the BrowserScriptHost, which delegates to the BrowserPAL class. Here’s a snippet I like to use to configure my my Ruby ScriptRuntime to use the BrowserScriptHost:
private ScriptRuntimeSetup GetSetup()
{
// Standard options
var typeName = typeof (RubyContext).AssemblyQualifiedName;
var displayName = "IronRuby";
var names = new List<string> {"IronRuby", "Ruby", "rb"};
var exts = new List<string> { ".rb" };
var setup = new ScriptRuntimeSetup();
setup.HostType = typeof(BrowserScriptHost);
setup.LanguageSetups.Add(new LanguageSetup(typeName, displayName, names, exts));
return setup;
}
// ...
var setup = GetSetup();
var runtime = IronRuby.Ruby.CreateRuntime(setup);
var engine = runtime.GetEngine("rb");
var context = (RubyContext)HostingHelpers.GetLanguageContext(engine);
Another indispensible trick is to add a REPL to the page:
// Insert REPL into DOM HtmlElement replDiv; var repl = Repl.Create(engine, engine.CreateScope(), out replDiv); HtmlPage.Document.Body.AppendChild(replDiv); repl.Start(); context.StandardOutput = repl.OutputBuffer; context.StandardErrorOutput = repl.OutputBuffer;
First, check out jetbrain’s documentation on the Scala plugin. Read through “Setting up the Environment” to figure out how to install the plugin. Next, create a project using steps 1 and 2 from “Hello World with Scala in 7 Steps”. Now, go through the rest of the steps and make sure everything is working. If you get the example working, congrats! You can stop reading this post and start hacking. If things didn’t turn out so peachy, keep reading.
Now, there’s a possibility that you’ll see the following error in your “Run” window:
java.lang.ClassNotFoundException
If so, you’ll need to “refresh” the project settings. Follow these steps:
That should fix the project. The reason you might need to do this is because the Scala compiler and library settings are not set properly. Touching these settings once will cause these settings to be properly configured.
This was a royal pain in the ass to figure out, so hopefully this’ll save you or someone else some time. What follows is pretty much copied verbatim from the following site:
http://www.noah.org/wiki/SSH_public_keys
Note to Windows/msysgit users: the following commands will work without a hitch if you run them from the “GIT Bash”. Otherwise, you’ll need to ensure that openssl is on your PATH. I’m assuming here that your key is located at %userprofile%/.ssh/id_rsa.
If your existing key is encrypted (read: has a password), you’ll need to remove the encryption first (this will obviously overwrite the existing key file):
openssl rsa -in ~/.ssh/id_rsa -out ~/.ssh/id_rsa
Once you’ve unencrypted your key, you’ll need to re-encrypt it (this will obviously overwrite the existing key file):
openssl rsa -des3 -in ~/.ssh/id_rsa -out ~/.ssh/id_rsa
When you run the above command, you’ll be prompted for your new password.
Tags: ssh
Trying to change the Datasource for your report? Too bad- you can’t…
http://forums.sdn.sap.com/thread.jspa?threadID=1501902&start=0&tstart=0
… unless you manually set the “Overriden Qualified Table Name” property under “Set Datasource Location”.
Thanks Crystal Reports for blowing several hours of my life away.
I’m no COM wizard, but I did learn something interesting today. C# allows you to “new up” a COM interface from a PIA as if it were a class. This caught me by surprise today when I was playing around with COM & IronRuby – I couldn’t instantiate COM objects like I could in C#!
Out of curiosity, I disassembled (using Reflector ) a snippet of C# code where I was instantiating an Outlook Applicaition; here’s what I found:
// This...
var app = new Microsoft.Office.Interop.Outlook.Application();
// ... is compiled like this:
var app =((Microsoft.Office.Interop.Outlook.Application)
Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("0006F03A-0000-0000-C000-000000000046")), args));
Isn’t that fascinating! How is the C# compiler finding the correct CLSID for the Outlook.Application interface?
I’m not really sure… but here’s my stab at pulling this off:
// Get the PIA assemby name, using the GUID of the typlib.
// Alternatively, we can skip this if we already know the assembly name.
string asmName;
string asmCodeBase;
var conv = new System.Runtime.InteropServices.TypeLibConverter();
conv.GetPrimaryInteropAssembly(new Guid("00062FFF-0000-0000-C000-000000000046"), 9, 3, 0, out asmName, out asmCodeBase);
// Load the PIA, and get the interface type
var assembly = System.Reflection.Assembly.Load(asmName);
var type = assembly.GetType("Microsoft.Office.Interop.Outlook.Application");
// Get the coclass
var coClassAttr = (System.Runtime.InteropServices.CoClassAttribute)
type.GetCustomAttributes(typeof(System.Runtime.InteropServices.CoClassAttribute), false)[0];
var coClass = coClassAttr.CoClass;
// Get the CLSID
var clsid = coClass.GUID;
You can also do pretty much the same thing in IronRuby (although you really should use WIN32OLE):
# The typlib details
ol_guid = System::Guid.new("00062FFF-0000-0000-C000-000000000046".to_clr_string)
ol_major = 9
ol_minor = 3
ol_lcid = 0
# Get the PIA's assembly name
conv = System::Runtime::InteropServices::TypeLibConverter.new
result, asm_name, asm_code_base = conv.GetPrimaryInteropAssembly(ol_guid, ol_major, ol_minor, ol_lcid)
# Load the assembly
require asm_name
include Microsoft::Office::Interop
def create_com_object(com_module)
coClass = com_module.to_clr_type.get_custom_attributes(
System::Runtime::InteropServices::CoClassAttribute.to_clr_type, false)[0].CoClass
System::Activator.CreateInstance(coClass)
end
app = create_com_object(Outlook::Application)
As I mentioned above, using WIN32OLE is a much better idea:
require 'win32ole'
app = WIN32OLE.new('Outlook.Application')
Look like I’m going to be busy figuring out how to extend Visual Studio 2010… just for the fun of it. I know the Spark View Engine’s VS2010 integration needs some work… perhaps I’ll start there.
Arclite theme by digitalnature | powered by WordPress