MIX09 Session Videos – How I Did It
On my last post I introduced the feeds I created to subscribe to Mix09 session videos.
In case someone is interested on how I did it, here it is:
<%@ WebHandler Language="C#" Class="mix09" %> using System; using System.IO; using System.Web; using System.Linq; using System.Xml.Linq; using System.Net; using System.Xml; public class mix09 : IHttpHandler, IHttpAsyncHandler { class WebClientOpenReadAsyncResult : IAsyncResult { private AsyncCallback callback; public WebClientOpenReadAsyncResult() { this.IsCompleted = true; this.CompletedSynchronously = true; } public WebClientOpenReadAsyncResult(AsyncCallback callback) { this.callback = callback; this.IsCompleted = false; this.CompletedSynchronously = false; } public object AsyncState { get { return null; } } public bool CompletedSynchronously { get; private set; } public System.Threading.WaitHandle AsyncWaitHandle { get { throw new InvalidOperationException("ASP.NET should not use this property ."); } } public bool IsCompleted { get; private set; } public Stream Stream { get; private set; } public void Completed(object sender, OpenReadCompletedEventArgs e) { this.IsCompleted = true; this.Stream = e.Result; if (this.callback != null) { this.callback(this); } } } private static Uri mixSessionsUri = new Uri("http://sessions.visitmix.com/RSS"); private HttpContext context; private string type; #region IHttpHandler Members public bool IsReusable { get { return true; } } public void ProcessRequest(HttpContext context) { WebClient wc = InitializeRequest(context); if (wc == null) { return; } OutputFeed(wc.OpenRead(mixSessionsUri)); } #endregion #region IHttpAsyncHandler Members public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) { WebClient wc = InitializeRequest(context); if (wc == null) { return new WebClientOpenReadAsyncResult(); } WebClientOpenReadAsyncResult ar = new WebClientOpenReadAsyncResult(cb); wc.OpenReadCompleted += ar.Completed; wc.OpenReadAsync(mixSessionsUri, extraData); return ar; } public void EndProcessRequest(IAsyncResult result) { Stream stream = (result as WebClientOpenReadAsyncResult).Stream; if (stream != null) { OutputFeed(stream); } } #endregion private WebClient InitializeRequest(HttpContext context) { this.context = context; this.type = context.Request.QueryString["type"]; if (string.IsNullOrEmpty(this.type)) { return null; } WebClient wc = new WebClient(); wc.Headers[HttpRequestHeader.UserAgent] = "Required User Agent"; return wc; } private void OutputFeed(Stream source) { XmlReader feedReader = XmlReader.Create(source); XDocument feed = XDocument.Load(feedReader); var rss = feed.Element("rss"); var channel = rss.Element("channel"); var title = channel.Element("title"); title.Value = string.Format("{0} ({1})", title.Value, this.type.ToUpper()); channel.Element("link").Value = "http://cli.gs/Mix09Sessions"; foreach (var item in channel.Elements("item")) { string link = item.Element("link").Value; string session = link.Substring(link.LastIndexOf('/') + 1).ToLower(); string enclosureUrl = string.Format("http://mschannel9.vo.msecnd.net/o9/mix/09/{0}/{1}.wmv", this.type.ToLower(), session); item.Add( new XElement("enclosure", new XAttribute("url", enclosureUrl))); } this.context.Response.Write(feed.ToString()); this.context.Response.ContentType = "application/rss+xml"; HttpCachePolicy cache = this.context.Response.Cache; cache.SetCacheability(HttpCacheability.ServerAndPrivate); cache.SetExpires(DateTime.Now.AddHours(1)); cache.VaryByParams["type"] = true; cache.SetValidUntilExpires(true); } }
MIX09 Session Videos
Updated (2009Mar25): Added MP4 feed.
Mix09 is over and I would like to watch some sessions.
I like to watch these kind of videos by subscribing them using the Zune Software as a podcast. I like the Zune Software because it downloads the “episodes” and I can watch them in any order and it never forgets where I was – even if I was watching it in the Zune.
Unfortunately, the only feed available (http://sessions.visitmix.com/RSS) does not include the videos.
Fortunately, the address of the videos is very predictable and I was able to build my own feeds:
- WMV-HQ: http://feeds.paulomorgado.net/PauloMorgado/Events/Mix09/SessionVideos/wmv-hq
- WMV: http://feeds.paulomorgado.net/PauloMorgado/Events/Mix09/SessionVideos/wmv
- ZUNE: http://feeds.paulomorgado.net/PauloMorgado/Events/Mix09/SessionVideos/zune
- MP4: http://feeds.paulomorgado.net/PauloMorgado/Events/Mix09/SessionVideos/mp4
The session videos are not available in all formats for every session (at least, not now) but, if you subscribe to all, you’ll get videos for all the sessions.
Subscribe and enjoy.
ASP.NET Futures: Control ClientID Generation
ASP.NET is expected to have some improvements on the generation of client IDs.
Although this is a major improvement, it comes short by not allowing the generation of shorter client IDs for server controls.
My good friend Nuno Gomes has done some work on generating shorter client IDs for controls (*).
Jeff has taken it one step further with his How to shorten ASP.NET automatically generated control IDs article on CodeProject.
If you want to see a running example, check out http://www.biocompare.com/.
- ASP.NET Controls - Improving automatic ID generation : Introduction ( Part 1)
- ASP.NET Controls - Improving automatic ID generation : Concept ( Part 2)
- ASP.NET Controls - Improving automatic ID generation - Architectural Changes ( Part 3)
- ASP.NET Controls - Improving automatic ID generation : The ShortIDs Naming Provider (Part 4)
Microsoft, Eurocrats And Internet Explorer
I’m all against monopolies, so I’m glad the Eurocrats are putting my tax payer Euros to good use.
But it also got me thinking.
If I buy something like an operating system, I expect the vendor to be responsible for what I’m buying. Does anyone think Microsoft will ever accept any responsibility for software that it hasn’t built and is forced to bundle into its products. They probably make some disclaimer like “We didn’t build this. We were forced to put this here and we totally discourage its use.”. That will boost other browsers.
Probably the Eurocrats are planning to take that responsibility themselves. I think there’s a greater possibility for Microsoft to take responsibility for something they didn’t built and were forced to bundle into their products.
On the other hand, a personal computer is becoming something like an household appliance. Do you expect to download a timer for your microwave oven before being able to use it? I don’t.
Internet Explorer is built to be parte of Windows and to be freely used by any application running on Windows. Any other we browser could be built the same way, why aren’t they?
Why isn’t anyone thinking of forcing Microsoft to allow for third party components to replace parts of Internet Explorer? Probably because no one cares about build applications that are good Windows “citizens”.
Setting A Web Proxy Through Configuration In .NET Applications
Specially in enterprise environments, proxy servers are used to access the Internet.
In a Windows / Internet Explorer environments there is a proxy server configuration in Internet Properties > Connections > LAN settings > Proxy server.
Although these configurations are tightly connected to Internet Explorer, any well behaved Windows application should, at least, allow the user to choose to use them.
In applications targeting the .NET framework, these the proxy server can be set on a per call basis. Several networking classes have a Proxy property that receives a value implementing the IWebProxy interface.
In order for the Windows/ Internet Explorer configuration to be used, the application must be configured to use the default proxy settings.
This configuration is done in the machine or application file in the proxy element of the defaultProxy configuration section in the system.net section group:
<configuration> <system.net> <defaultProxy enabled="true"> <proxy usesystemdefault="True"/> </defaultProxy> </system.net> </configuration>
You can use this configuration also to set a specific proxy to be used by your application. In the following example, a proxy setting for using the Fiddler Tool is used:
<configuration> <system.net> <defaultProxy enabled="true"><proxy proxyaddress="http://ipv4.fiddler"/><proxy proxyaddress="http://127.0.0.1:8888"/> </defaultProxy> </system.net> </configuration>
Unfortunately, this is a MachineToApplication setting and, for that reason, is not allowed in the user settings configuration file, when in a shared installation. In these type of installations, the default Windows / Internet Explorer settings should be used as a default. If a user needs or wants to specify proxy server settings, application specific proxy server settings must be used but, assigning the user defined proxy server configuration to the GlobalProxySelection.Select property will allow its use for the entire application.
Updated: Corrected proxy address when using Fiddler following Eric Lawrence’s comment:
> <proxy proxyaddress="http://ipv4.fiddler/" />
That line should not work. Fiddler doesn't register anything in DNS, so for "ipv4.fiddler" to have any meaning, Fiddler must already be being used as the proxy.
The proper setting for Fiddler use should be:
<proxy proxyaddress="http://127.0.0.1:8888" />
Another Great Example Of Silverlight Deep Zoom – From ViaTecla Innovation Laboratories
This innovative use of Deep Zoom uses screenshots of sites powered by ViaTecla’s software solutions to form a picture of a Santa Claus.
Saved By The .NET Framework Cleanup Tool – Again!
I don’t know what’s wrong with my XP system (besides the fact that I’m still using it) but I couldn’t install .NET 3.5 without removing .NET 2.0 and now I couldn’t install apply SP1 without removing .NET 3.0 and 3.5.
Fortunately, I was rescued by Aaron Stebner’s .NET Framework cleanup Tool – both times.
Kudos Aaron!
How To Issue Server Callbacks
Callbacks were introduced in ASP.NET 2.0 and is a simple mechanism for calling page or control functionality without page rendering and without the user noticing a post back.
For a page or control to handle callbacks, all it needs is to implement the ICallbackEventHandler Interface.
When the client calls back to de page or control, the initial state of the controls is posted along with the control being called upon in the __CALLBACKID field and the callback parameter in the __CALLBACKPARAM field.
It’s quite a simple procedure.
But what if you want to issue a callback server side?
In order for a request to be identified as a callback (IsCallback), the request must be a postback (IsPostback) and the before mentioned fields must be in the post data of the request. On the other hand, for a request to be considered a postback, the level of server calls (Transfer or Execute) must be 0 (meaning that the current request hasn’t made any Transfer or Execute calls) or the type of the page is the same of the Handler for the current request and the HTTP method is POST.
Changing the HTTP method is (as far as I know) impossible. So, if the request is not already a POST, there’s no way to issue a callback.
Setting the post data is easier. All it’s needed is to override the page’s DeterminePostBackMode method (or in a page adapter) and return the post data previously saved in a context item. Something like this:
protected override NameValueCollection DeterminePostBackMode() { NameValueCollection postBackMode = Context.Items["callbackPostData"] as NameValueCollection; return (postBackMode != null) ? postBackMode : base.DeterminePostBackMode(); }
And issue a callback is something like this:
IHttpHandler handler = this.Context.Handler; try { NameValueCollection postData = new NameValueCollection(); postData.Add("__CALLBACKID", sender); postData.Add("__CALLBACKPARAM", this.argument.Text); Context.Items["callbackPostData"] = postData; Page calledPage = (Page)PageParser.GetCompiledPageInstance("~/Callback1.aspx", this.Server.MapPath("~/Callback1.aspx"), this.Context); this.Context.Handler = calledPage; StringWriter writer = new StringWriter(); Server.Execute(calledPage, writer, false); this.response.Text = writer.ToString(); } finally { this.Context.Handler = handler; }
You can find an implementation of a caller and a called page here.
Improving Debugging And Testing Through Assertions
Reading through the The Typemock Insider blog, I came across this post from Gil Zilberfeld.
I myself tend to fall in Gil’s practice ("binary search" debugging), but I don’t think Kent Beck has the right solution.
Gil’s suggestion of using Isolator is tempting (I don’t miss an opportunity to use it), but still not my favorite one.
I prefer to use debug assertions. Debug assertions can be used when running a debug version of the application to pop-up assertion messages and when running unit tests to fail tests.
In order to use debug assertions in unit tests a “special” trace listener is needed to make the test fail when its Fail method is called.
public class UnitTestTraceListener : global::System.Diagnostics.DefaultTraceListener { public UnitTestTraceListener() : base() { this.Name = "UnitTest"; this.AssertUiEnabled = false; } public override void Fail(string message, string detailMessage) { Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Fail("Debug.Assert Failed: " + message + " " + detailMessage); } }
Now, all you need to do is register it.
Registering the trace listener can either be done in code:
System.Diagnostics.Trace.Listeners.Remove("Default"); System.Diagnostics.Trace.Listeners.Add(new UnitTestTraceListener());
or configuration:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.diagnostics> <assert assertuienabled="false"/> <trace> <listeners> <clear/> <add name="UnitTest" type="UnitTestTraceListener"/> </listeners> </trace> </system.diagnostics> </configuration>
And if I’m using Isolator I have the take in account the accesses made in the call to the Assert method. More fun to me.
Recent Comments