I've started learning JavaScript in November 2009, so about 2 months ago. I am a WebForms developer in my Job, thanks to SharePoint, and I was fed up one day with static/postback-only user interfaces. I wanted to make them snappy, cool, Web 2.0™.
One of the things that kept me away from JavaScript in the past was the browser support hell. Every browser has little differences in it's implementation, and even trivial operation often require an if-statement with 3+ branches to get the differences straightened out. Luckily, libraries like jQuery are available to abstract the whole mess away and give us a clean interface to interact with the browser. I am a big fan of abstractions as long as I know what I'm abstracting away, and jQuery is pure gold that allows me to focus on the actual application/user interface I'm building. After lerning about JavaScripts scoping rules (variables are available to the entire function - { and } do not create a new scope) I was finally able to understand, troubleshoot, and (hopefully) fix a bug in a third party library that I'm using - finally being in control feels great!
But, I have one issue, which is the JavaScript support in Chrome and Firefox. This is a controversial statement for sure, as pretty much everyone agrees that Firefox and Firebug is the de-facto standard for JavaScript development, which I would normally agree with - as good as the Web Developer Toolbar became in Internet Explorer 8, Firebug is still the nicer tool. But my problem with Firefox and Chrome is that they are too lenient about bad JavaScript.
I'm guessing that this is because most JavaScript on the web is simply broken, and throwing an error every time an error is occurs would seriously degrade browsing experience. So I'm guessing that just as with broken HTML, "modern" browsers try to fuzz and fix the JavaScript. One of the reasons XHTML failed was because it was too strict, and because browsers didn't complain loud enough.
I had 3 hard to track down JavaScript errors. Well, hard to track down for me. In all three cases, the error was mine. An extra comma before a closing bracket, forgetting to close a bracket etc. Firefox worked flawlessly. Chrome had a subtle bug. The only browser that constantly does the right thing is Internet Explorer 8: It refuses to execute the JavaScript and throws an error instead.
When developing, this is what I want. I want any errors to be reported. I want the application to crash hard. I want the browser equivalent of -Wall and -Werror. Granted, the Internet Explorer error messages are not that helpful as they only roughly outline what the problem is, but still they are useful enough to work with.
As a developer, I still care about my code. I try to write valid HTML, valid CSS and valid JavaScript whenever possible and at least know when I'm breaking the rules in the cases where valid code is not feasible. So any functionality that sweetens the experience for the end user by hiding errors is making the experience for the developer worse. I know that there are many advocates of loose standards and "just somehow automatically fix it", but ultimately I think that standards exist for a reason and I'd like to at least know that I'm doing something wrong.
But then again, this is the Internet and I realize that design and content are much, much more important than code quality, and I agree that providing value to the customer is ultimately more important than having a solid code base. But still, please leave me my illusion that good code and web application are not mutually exclusive
This episode focuses on some advanced concepts with breakpoints, like conditions or exporting/importing them. We also look at the breakpoint window. After this episode, you should be able to use breakpoints more efficiently than just as on/off switches.
Okay, this took a little longer because of a broken Power Supply in my PC. Also, due to software problems, there are no titles, but I didn't want to wait much longer. If you happen to know a proper Video Editing solution for Windows, please answer this SuperUser question
Yesterday, I spent an hour setting up a Debian Linux VM to host a MediaWiki, which is now a 1.2 GB big folder in the /doc folder of a new project, checked into SVN. While I was doing that despite the utter stupidity behind it, I was remembering that I tried to create a better Wiki System a few months back with SWiki. Now SWiki is nice in theory, but I think I made some fundamentally wrong decisions in it's scope and in the end, I didn't want to use it myself for anything. So I was thinking again about what problem I tried to solve and what I want to achieve.
MediaWiki is a fantastic system, but it requires a LAMP Stack to really work, and the fact that all data is in a database doesn't make it very Source Control friendly. So I really wanted to solve two different problems: I wanted all the data in the file system, so that it can be checked into source control and easily be shared by other people. So no database server. But to share it with other people, they need to be easily able to read the files. I did not want an application that digs deep into the system. Ideally, I do not want to require installation at all and leave no marks in the system.
So the original SWiki solved problem 1 by using a SQLite Database. There is nothing wrong with using a database as long as it's 100% filesystem based. My attempt at Problem 2 was to host the Internet Explorer COM Object Microsoft exposes and feed it HTML. That way, I don't even need a web server. But that attempt ultimately proved a failure. I could not do much of the rich formatting I wanted, even embedding images was impossible. At some point I questioned whether my use of HTML was correct, or if I shouldn't just use RTF and embed stuff using OLE.
But my problem wasn't the Markup part. I like the WikiPlex markup, and the library is clean and extensible. I really didn't want to try using OLE/RTF as these technologies are not meant for human consumption. Also, I want to keep the ability to export the Wiki to HTML so that it can be hosted on a real web server if desired (e.g., the documentation section of a project).
So really, I need a Web Server. But I don't need a particularly "good" one, especially because I do not want a large "footprint" in the network. Really, running a web server is a great way to trigger all sorts of security software across the entire company. But without a webserver, SWiki is simply not good. So I've started looking at the Cassini Web Server, which is conveniently open source under Ms-PL. This is a great server for many reasons. One, it's 100% managed code, so it can be completely embedded in my app. But more importantly, it can be configured to only ever listen on local loopback, that is 127.0.0.1 for IPv4 or ::1 for IPv6. This may still trigger some security software, but it seals off the application from the network, so no interruption should be caused in theory.
Overall, this is a good compromise. I gain the ability to turn SWiki into a full-blown ASP.net application by simply bundling it with a lightweight web server and control utility, all while still being able to keep the data in a single file. So this is what I will do now. I haven't decided if I keep SQLite as database or use SQL Compact due to it's much better integration and if I'm able to offer an upgrade for databases between "SWiki old" and "SWiki new". I haven't even decided if I keep the name or change it, although the existence of another wiki by that name makes me want to change it.
The only thing I really have decided on is that it will support images and that it will still use WikiPlex as it's parser, all while still requiring .net 3.5 and all while - at it's core - still being a simple, standalone desktop wiki, although a little bit less simple than originally envisioned.
I've been starting to pick up ASP.net AJAX again, mainly because as a SharePoint developer I will be "stuck" with WebForms 3.5 for the next few years (SharePoint 2010 will not be a .net 4.0 application). As part of that, I remembered one issue I had: The UpdateProgress renders a div with display:block set, which means it is not possible to have the updateProgress right next to a button. Joe Audette had the right idea: Grab the UpdateProgress from the Mono Project and modify it. The nice thing about the Class Libraries of Mono is that they are licensed under the very liberal MIT X11 license, making them good candidates as a base for modifications.
Here is the source code of the UpdateProgressEx, which includes a new Property, DisplayInline. If this is set to true, then we render a span with display: inline. If this is set to false or not set at all, we have the default behavior of a div/block. If DisplayInline is set to true, then we force DynamicLayout to be false. Why? Because if DynamicLayout is true, then it seems like the MS AJAX JavaScript control the display, and they render it as a block. As I did not want to modify it any further, I just force DynamicLayout to false because for me, that works good enough. Also, I haven't tested if it works in visual design mode and if the property panel shows the new DisplayInline Property, as I work only in code view. YMMV, but it's Open Source after all, so feel free to properly fix it
Here is the code:
// UpdateProgressEx
//
// Author:
// Michael Stum <website@stum.de>
// http://www.stum.de/2010/01/28/an-asp-net-ajax-updateprogress-that-can-render-inline
//
// Original Author:
// Igor Zelmanovich <igorz@mainsoft.com>
// (C) 2007 Mainsoft, Inc. http://www.mainsoft.com
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Web.UI;
namespace StumDE.WebControls
{
[PersistChildren(false)]
[ParseChildren(true)]
[DefaultProperty("AssociatedUpdatePanelID")]
[Designer("System.Web.UI.Design.UpdateProgressDesigner, System.Web.Extensions.Design, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")]
public class UpdateProgressEx : Control, IScriptControl
{
ITemplate _progressTemplate;
ScriptManager _scriptManager;
[Category("Behavior")]
[DefaultValue("")]
[IDReferenceProperty(typeof(UpdatePanel))]
public string AssociatedUpdatePanelID
{
get
{
return (string)ViewState["AssociatedUpdatePanelID"] ?? String.Empty;
}
set
{
ViewState["AssociatedUpdatePanelID"] = value;
}
}
[Category("Behavior")]
[DefaultValue(false)]
public bool DisplayInline
{
get
{
object o = ViewState["DisplayInline"];
if (o == null)
return false;
return (bool)o;
}
set
{
ViewState["DisplayInline"] = value;
}
}
[Category("Behavior")]
[DefaultValue(500)]
public int DisplayAfter
{
get
{
object o = ViewState["DisplayAfter"];
if (o == null)
return 500;
return (int)o;
}
set
{
ViewState["DisplayAfter"] = value;
}
}
[Category("Behavior")]
[DefaultValue(true)]
public bool DynamicLayout
{
get
{
// If DisplayInline is set, force dynamic layout to be false
if(DisplayInline) return false;
object o = ViewState["DynamicLayout"];
if (o == null)
return true;
return (bool)o;
}
set
{
ViewState["DynamicLayout"] = value;
}
}
[PersistenceMode(PersistenceMode.InnerProperty)]
[Browsable(false)]
public ITemplate ProgressTemplate
{
get
{
return _progressTemplate;
}
set
{
_progressTemplate = value;
}
}
ScriptManager ScriptManager
{
get
{
if (_scriptManager == null)
{
_scriptManager = ScriptManager.GetCurrent(Page);
if (_scriptManager == null)
throw new InvalidOperationException(String.Format("The control with ID '{0}' requires a ScriptManager on the page. The ScriptManager must appear before any controls that need it.", ID));
}
return _scriptManager;
}
}
protected virtual IEnumerable<ScriptDescriptor> GetScriptDescriptors()
{
string updatePanelClientId;
if (String.IsNullOrEmpty(AssociatedUpdatePanelID))
updatePanelClientId = null;
else
{
var updatePanel = FindControl(AssociatedUpdatePanelID) as UpdatePanel;
if (updatePanel == null)
throw new InvalidOperationException("No UpdatePanel found for AssociatedUpdatePanelID '" + AssociatedUpdatePanelID + "'.");
updatePanelClientId = updatePanel.ClientID;
}
var descriptor = new ScriptControlDescriptor("Sys.UI._UpdateProgress", this.ClientID);
descriptor.AddProperty("associatedUpdatePanelId", updatePanelClientId);
descriptor.AddProperty("displayAfter", DisplayAfter);
descriptor.AddProperty("dynamicLayout", DynamicLayout);
descriptor.AddProperty("displayInline", DisplayInline);
yield return descriptor;
}
protected virtual IEnumerable<ScriptReference> GetScriptReferences()
{
yield break;
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
ScriptManager.RegisterScriptControl(this);
if (_progressTemplate == null)
throw new InvalidOperationException(String.Format("A ProgressTemplate must be specified on UpdateProgress control with ID '{0}'.", ID));
var container = new Control();
_progressTemplate.InstantiateIn(container);
Controls.Add(container);
}
protected override void Render(HtmlTextWriter writer)
{
if (DynamicLayout)
writer.AddStyleAttribute(HtmlTextWriterStyle.Display, "none");
else
{
writer.AddStyleAttribute(HtmlTextWriterStyle.Display, DisplayInline ? "inline" : "block");
writer.AddStyleAttribute(HtmlTextWriterStyle.Visibility, "hidden");
}
writer.AddAttribute(HtmlTextWriterAttribute.Id, ClientID);
if (DisplayInline)
{
writer.RenderBeginTag(HtmlTextWriterTag.Span);
}
else
{
writer.RenderBeginTag(HtmlTextWriterTag.Div);
}
base.Render(writer);
writer.RenderEndTag();
ScriptManager.RegisterScriptDescriptors(this);
}
#region IScriptControl Members
IEnumerable<ScriptDescriptor> IScriptControl.GetScriptDescriptors()
{
return GetScriptDescriptors();
}
IEnumerable<ScriptReference> IScriptControl.GetScriptReferences()
{
return GetScriptReferences();
}
#endregion
}
}
For a Project I had on a SharePoint site I thought it would be a good idea to create a new master page that is based on the default.master and exposes some placeholder for my content pages to use. Nested Master Pages are trivial to do in ASP.net normally, but for some reason on my SharePoint site, the child page was not rendering its content in one of the new placeholders.
Well, turns out that SharePoint 2007/WSSv3 explicitly does not support nested master pages. To quote an Article in MSDN directly:
Although the underlying technology enables the creation of nested master pages, nested master pages are not supported in Windows SharePoint Services. Using nested master pages can cause unexpected behavior in some scenarios, such as preventing content from rendering.
Indeed, unexpected behavior, such as content not rendering is the exact problem I have. Now I remember why I love SharePoint so much: It's taking the essential functions of ASP.net and then adds some traps that really hurt you unexpectedly.
The first episode in the Debugging in Visual Studio 2010 series is about the most fundamental concept of all, Breakpoints. Also, we cover the Locals window, which is the first additional window of the debugger.
As this is the first episode, there are some kinks I haven't manage to fully iron out. The audio quality isn't perfect, mainly because the Microphone I specifically bought for stuff like this turned out to be junk and I had to use the one in my Webcam. Also I experimented with having a script vs. speaking freely and tend to overuse the phrase "You may notice" quite a bit...
You can watch the video in higher, full HD quality directly on Vimeo.
I found that if I want to learn something, I should try explaining or teaching it to someone else. As I work as a SharePoint Developer, the Debugger became my best friend very quickly, but I always ever only touched the surface and maybe a little bit more. A recent problem requires me now to dig really deep and is forcing me to really learn to use the debugger. So I thought this would be an excellent opportunity to create a little video series, of which the first chapter will be "Beginning Debugging in Visual Studio 2010". Now let me first start with a disclaimer: I am still learning this stuff. I am not a senior developer at Microsoft with 20 years experience writing operating system, I am just someone who picked up C# 4 years ago and is now trying to learn through teaching.
This series is not about design or architecture, it is not about unit testing or best practices. This is purely about having some buggy code and using the debugger to find the issue and solve it. This is about moving from trial-and-error/guessing to evidence-gathering.
There is no set schedule for releases and I am not sure how many episodes there will be. I do have plans for three chapters of varying "difficulty" and I do have a to-do list of stuff I want to cover, but as some items on this list are really hardcore I'm not sure what will come out of this.
Anyway, here is an index to all released episodes:
Chapter One: Beginning Debugging in Visual Studio 2010
So we have a bool that we switch on every iteration and then we derive the CSS Class Name from that. If you do that in one place, it's okay, but if you have to do that in many places, it can become quite a bit tedious. Sure, if you happen to use a for-loop you can just use "index % 2 == 0" to find out if you are on an even row, but I instead created a class:
public class EvenOddCycler
{
private readonly string _oddClassName;
private readonly string _evenClassName;
private int _numCycles;
public EvenOddCycler() : this("evenRow","oddRow"){}
public EvenOddCycler(string evenClassName, string oddClassName)
{
_evenClassName = evenClassName;
_oddClassName = oddClassName;
_numCycles = 0;
}
public string Cycle()
{
_numCycles++;
return IsCurrentlyEven ? _evenClassName : _oddClassName;
}
public void Reset()
{
_numCycles = 0;
}
public bool IsCurrentlyEven
{
get { return (_numCycles % 2 == 0); }
}
}
Really simple stuff here: The constructor takes two strings, one for even and for odd. It has a Cycle function that increases a counter and returns one of the two strings. Also included a Reset() function to re-use the cycler in case you have more than one table on a page.
The usage looks like this:
var cycler = new EvenOddCycler();
foreach (var item in someList)
{
SomeTable.Rows.Add(SomeFunctionThatReturnsATableRow(item,cycler.Cycle()));
}
What did we gain?
No need to constantly repeat the class names over and over again. You shouldn't hardcode them, but even if you put it in a Resource class of some kind, you still have to have the boolean switch somewhere to get the correct class name. No need here anymore.
No need to copy/paste this if you have multiple tables on a Page. Just call cycler.Reset()
Granted. it's a small thing, but every little thing I don't have to worry about is good.
This is not Thread-safe because I see no scenario where you would share one cycler. Making it Thread-safe is a simple matter of adding a lock object and locking all three method bodies though.
Okay, so my system Hard Drive isn't too big, only 139 GB. But it's a 10k Raptor, so for the time being it will have to suffice until SSDs get good and affordable.
To my shock, today it was full:
While checking what took so much space, I found quite a few things, but one caught my attention, the Hibernate file:
I have 8 Gigabytes of RAM in my machine, so I have to live with a large Page File (no, I'm not disabling it. If even Mark Russinovich advises against disabling it, that counts more), but I certainly do not need the Hibernate file as this is a Desktop PC that's either running or off.
Weirdly, I couldn't find any option in Windows 7 to do so.Not sure if it's me or if there really is none, but it can easily be done on the command line. Run an elevated command prompt (cmd.exe, Run As Administrator) and type in
powercfg /hibernate off
The Hiberfil.sys should now be gone and the disk space should be free again.
I remember playing around with VMWare Workstation around 2000 when it was a new idea. It seemed awesome, as I was working in a PC Shop at the time serving both German and English customers. We ran Windows 2000 on our Work machines, but our customers usually had Windows 98 SE or Windows ME. With VMWare, I could install German and English Windows 98 and ME and troubleshooting became a lot easier.
Fast forward to the present day. VMs are a staple in the toolset of every developer now. Need to test your app on Windows XP, Vista and 7? Need to test deployment on both Server 2003 and 2008? Need a legacy Internet Explorer 6 machine? Or want to give Linux a spin? Great, just create a VM. Virtualization products are available for free now, thanks to Microsoft giving away VirtualPC and VMWare giving away their VMWare Server.
Now, VirtualPC is rather useless sadly, as it can not run 64-Bit Guests. Yup, surprised me as well. On the other hand, VMWare Server isn't really well suited for Desktops - it goes "too deep" into the system and it's whole interface is more aimed at remote usage (you can't select an .iso file on your hard drive unless you previously added it to a list of known locations...). There was a different free VMWare product though, VMWare Player.
The first versions could only run, but not create Virtual machines. They were great to run Live Systems/Appliances, for example Mono. Needless to say, soon sites like EasyVMX emerged to allow creating new Virtual Machines, so that Player was a full VM solution. So yesterday I installed the newest VMWare Player 3, already prepared to head to EasyVMX to create my VM. But then I was pleasantly surprised - Player now creates VMs!
And VMWare really went all out here. At least for Windows, they automatically detect your Operating System and offer Easy Install:
Easy Install means that it will do an unattended installation - you only have to enter your Product Key and maybe a password, then you can lean back and wait until it presents you with the Login Screen of a fresh Windows installation.
This, my dear friends, is awesome! I don't have much use for the advanced features of VMWare Workstation, so Player is my solution of choice - and Player 3 is a significant update!
Well done, VMWare! I wonder if Microsoft will ever catch up? XP Mode in Windows 7 is kinda nice, but I'd rather setup an XP VM in Player than installing a 32-Bit-only Virtual PC.