In my last post, I mentioned that PowerShellASP doesn’t work for files stored in a SharePoint content database. It wasn’t hard to track down why this is the case, so my next step was to attempt a fix.
First, a recap of the relevant code. In PSHandler.ProcessRequest(HttpContext)
, the entry point for the handler, we have:
string filename = A_0.Request.MapPath(A_0.Request.FilePath); ... this.a(filename);
MapPath
doesn’t know to do anything special with content files, so it returns a useless path which is then passed to PSHandler.a(String A_0)
and used here:
using (StreamReader reader = new StreamReader(A_0)) { ...
Rather than modify the existing handler (much), I propose creating a SharePoint-specific handler that inherits from PSHandler
. Before we can do that, we need to refactor the original slightly to facilitate the extension.
The biggest change is extracting the contents of the using(StreamReader)
block into a new protected method that accepts a StreamReader
:
using (StreamReader reader = new StreamReader(A_0)) { this.a(reader); }
We should also change the private HttpContext
field to protected, which I will call _a
for our example. Now we have everything we need to extend PSHandler
:
public class SPPSHandler : PSHandler, IHttpHandler { public new void ProcessRequest(HttpContext context) { base._a = context; HttpRequest request = context.Request; string filePath = request.FilePath; string mappedPath = request.MapPath(filePath); if (File.Exists(mappedPath)) using (StreamReader sr = new StreamReader(mappedPath)) { base.a(sr); return; } SPContext currentContext = SPContext.Current; if (currentContext != null) { SPWeb web = currentContext.Web; SPFile file = null; if (web != null && (file = web.GetFile(filePath)) != null && file.Exists) using (StreamReader sr = new StreamReader(file.OpenBinaryStream())) { base.a(sr); return; } } // Quoth the server... context.Response.StatusCode = 404; } }
A theoretical subclass is great and all, but does it work? Well we can’t change the original assembly, and I don’t feel like messing with reflection, so let’s build a mock PSHandler
instead:
public class PSHandler : IHttpHandler { protected HttpContext _a; public bool IsReusable { get { return true; } } public void ProcessRequest(HttpContext A_0) { this._a = A_0; A_0.Response.Write("PSHandler"); // Shouldn't see this } protected void a(StreamReader reader) { TextWriter o = _a.Response.Output; o.Write("<html><body><pre>"); o.Write(SPEncode.HtmlEncodePreserveSpaces(reader.ReadToEnd().ToUpper())); o.Write("</pre></body></html>"); } }
After adjusting the feature receiver to reference our new handler, we see that it does indeed behave as expected:
I haven’t tested extensively, but it’s a start. I doubt the PoShASP team would bother with these changes just for me, so if you’re at all interested leave a comment or at least contact them.
July 29, 2008 at 7:34 pm
[…] PowerShellASP with SharePoint: Scripts in Content Database […]