ASP.net MVC RC1 - ViewData.Model becomes Model
With RC1, the team has added a top-level property to access the Model for the page. As such:
Becomes:
Both work the same, however the second is just a little bit cleaner as you don’t need to go via ViewData…
Labels: ASP.net MVC
ASP.net MVC RC1 – Removing Code Behind files
With ASP.net MVC, one thing I always wondered is why we still had to have the code behind files. Looking at the FubuMVC samples, everything looks much cleaner without the additional files – with RC1, code-behind files are no longer required!
However, if your upgrading from beta, you will need to change your ASPX pages. In this post, I will cover the steps I went through to remove these files.
During beta, my solution looked looked like this:
In my code behind, I have a mixture of strongly typed ViewPage<T> objects and the standard ViewPage. As a result, in my ASPX page, I had a CodeBehind file and a Inherits tag.
With RC1, I can remove the CodeBehind tag and replace the Inherits to System.Web.MVC.ViewPage directly.
I can now delete Index.aspx.cs and Index.aspx.designer.cs leaving me with just the Index.aspx file.
If my ViewPage was strongly typed with a model, the the Inherits tag would include this, just like with the code behind model:
For ASP.net MVC User Controls, instead of ViewPage<T> you use ViewUserControl<T>:
Similarly with Master Pages:
After changing all my views, controls and master pages, my solution looks like this:
This makes me happy.
UPDATE: Parser Error Message: Could not load type 'System.Web.Mvc.ViewPage<ProductsMenuModel>'.
Ok – I made a little mistake. When I hit my ViewPage<T>, I received a Parser error message. If I had paid more attention to the release notes, I would have noticed I needed to copy an additional block of xml into my web.config.
<pages
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<controls>
<add assembly="System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
</controls>
</pages>
Labels: ASP.net MVC
Upgrading a project from ASP.net MVC Beta to ASP.net MVC RC1
As I'm sure you are well aware, the ASP.net team have released ASP.net MVC RC1 tonight. Eager to find out how much additional work I had, I downloaded and upgraded my solution – I was pleasantly surprised.
All I had to do was:
- Uninstall beta bits
- Install RC1 bits
- Update project references for System.Web.Abstractions.dll, System.Web.Mvc.dll and System.Web.Routing.dll
- Build
- Test
- Done!
Following my own advice, I commit the updated installer and assemblies into source control. Everything appears to be working, but I guess your mileage may vary.
Labels: ASP.net MVC
Annotating Code with .NET Reflector and Review Add-In
My latest article for Simple Talk has just been published. In the article, I cover how you can use the reflector addin ‘Peli’s Review’ from CodePlex that allows you to add annotations about your .Net assemblies from within reflector.
You can read it here:
http://www.simple-talk.com/dotnet/.net-tools/annotating-code-with-.net-reflector-and-review-add-in/
Labels: Red Gate, Reflector, Simple Talk
Identify the location of your SQL Server databases using T-SQL
While creating a series of test databases, I was required to hardcode a location to store the files. This caused me a problem as I wanted the script to be reusable on different machines \ platforms while also being consistent. I couldn’t enter the path for the SQL Server data files as this can be different, and I couldn’t enter a different path because it might not exist and I wasn’t keen on creating directories via T-SQL and xp_cmdshell.
While, it turns out you can find the location of your default SQL Server store simply by querying the system tables –sysaltfiles and getting the path for a particular database such as master.
DECLARE @device_directory NVARCHAR(MAX)
SELECT @device_directory = SUBSTRING(filename, 1, CHARINDEX(N'master.mdf', LOWER(filename)) - 1) FROM master.dbo.sysaltfiles WHERE dbid = 1 AND fileid = 1
After executing the query, on my local machine the value of @device_directory is ‘C:\Program Files\Microsoft SQL Server\MSSQL.3\MSSQL\DATA\’
The variable can then be used when creating the files, for example filegroups for your database.
EXECUTE (N'CREATE DATABASE Northwind
ON PRIMARY (NAME = N''Northwind'', FILENAME = N''' + @device_directory + N'northwnd.mdf'')
LOG ON (NAME = N''Northwind_log'', FILENAME = N''' + @device_directory + N'northwnd.ldf'')')
go
Labels: SQL Server
Unable to access or ping Windows 2008 server
After being bitten by this for the second time, I thought I should write a post for future reference. I had setup a brand new virtual machine and I wanted to access the SQL Server 2008 instance. Because of the firewall built into Windows all external connections are blocked – this means I cannot ping the machine, let along connect to the SQL Server instance running.
Disabling the firewall isn’t a problem, in the control panel you simply set the option.
Generally, this solves the problem. However, after doing this on 2008, I still couldn’t ping the machine. After paying a bit more close attention, I found that the Windows 2008 Firewall has different profiles, each with their own firewall setting. While I had disabled the firewall for the domain, public and private where still active and blocking my connection.
After disabling the firewall on both of those profiles, I could happily ping the machine and connect to the SQL Server Instance running.
Labels: SQL Server 2008, Windows 2008
IronTwitter - Sending a tweet from the IronRuby REPL
In my previous post, I discussed how to parse XML from a REST service. As it happens, the REST service I was interested in was the Twitter API. My aim was to use IronRuby to update my Twitter status from the REPL (Read-eval-print loop) – the interactive console. The result is IronTwitter :)
While I'm no expert on REST, I understand that you simply ping a URL with a correctly formed URL and process the response in the correct format (xml, json etc).
One of the great things about IronRuby is the REPL, this is the ir.exe console application and allows you to interact with the language and .net at runtime, they are very simple – type a line, hit enter and the line is executed. They are great for executing quick lines of code, or learning how do a task in the language. I used the REPL a lot while creating the XML parser as I could easily modify the code dynamically to see if something worked as I expected.
Interacting with IronTwitter
Interacting with IronTwitter is very easy. First you need to reference the library.
require 'IronTwitter'
You then need to construct the object, providing your username and password
@twitter = IronTwitter.new 'username', 'password'
The IronTwitter object has a method called update which has a parameter for your new status. Under the covers, it calls the API and updates your status. However, in order to make this easier to type, I added an alias for the method called t. To update your status, you simply type.
@twitter.t "Hello from IronTwitter!"
This will send a request to ‘http://twitter.com/statuses/update.xml?status=Hello from IronTwitter!’ and your twitter status will be updated.
We can now start taking advantage of IronRuby and we can start constructing tweets dynamically! For example, if we had a method which counted all the files and directories, we could tweet the result.
def count(dir)
num = 1
Dir[dir + '/*'].each do |d|
if File.file? d
num = num + 1
else
num = num + count(d)
end
end
return num
end
All we would need to do is call the method and join the response onto the string argument for the method.
twitter.t 'The number of files currently in %TEMP% is ' + count('C:/Users/BENHAL~1/AppData/Local/Temp').to_s
While this isn’t the most interesting tweet, it’s an interesting concept. You can see my various test tweets at http://twitter.com/ben_hall_test, note my main twitter account is http://twitter.com/ben_hall.
After being able to send a tweet, I wanted to see how to process the response. The API has a FriendsTimeline method, this will return the timeline you see on your twitter homepage, the tweets of you and the people your following. Using my xml wrapper, when you call the method friends_timeline, you then use a block to process each status, which is a monkey patched XmlElement object from the Xml Parser I created.
>>> @twitter.friends_timeline {|status| puts status.get('text')}
Hello from IronTwitter!
…..
Under the covers of IronTwitter
While that is very interesting, what happens under the covers is more relevant. When dealing with the API, there are two important items, the first is the url, the second is the options. For update, I send a request to ‘statuses/update.xml’ with a parameter status containing my message.
def update(msg)
url = "http://twitter.com/statuses/update.xml"
options = { :status => msg }
send_request url, options
end
alias :t :update
This is then passed into my send_request method, this uses the WebRequest object from System.Net to send the correctly formatted request.
def send_request(url, options)
requestUrl = convert url, options
request = WebRequest.Create(requestUrl)
request.Method = "POST";
request.ContentType="application/x-www-form-urlencoded";
request.ContentLength = 0;
request.UserAgent = "IronTwitter"
request.Credentials = NetworkCredential.new(@username, @password)
@response = request.GetResponse
end
The URL which is requested looks like this. As we use HTTPAuth, your status is updated.
http://twitter.com/statuses/update.xml?status=Hello from IronTwitter!
A similar approach is taken when it comes to the friends timeline. First, I've used an optional parameter so you can define the limit of statuses returned – by default it is 20. The method then takes a block, this is used to process the request. If a block is not provided, I raise an exception. I then use the Xml Parser I created to start processing the xml response.
def friends_timeline(tweetCount=20, &b)
url = "http://twitter.com/statuses/friends_timeline.xml"
options = { :count => tweetCount }
send_request url, options
readStream = System::IO::StreamReader.new(@response.GetResponseStream)
doc = Document.new(readStream.read_to_end)
if block_given?
doc.elements('statuses/status') do |status|
b.call status
end
else
raise 'Block required for processing statuses'
end
end
From the calling code, I simply access the elements on the node and output them to the screen.
twitter.friends_timeline do |status|
status.node('user') {|u| print u.get('name') }
print ' '
puts status.get('text')
end
The name and the status of the user is then sent to the console, the result being this:
E:\IronTwitter>ir sample.rb
Ben Hall This is a test tweet
Download the code and sample from here. I’ve also uploaded the code to the MSDN Code Gallery
Parsing XML using IronRuby
Today I have been looking at how you can use IronRuby to communicate with the various REST API’s floating around the web. Most of the services, such as flickr or twitter, allow you to select the format of the response. While JSON (JavaScript Object Notation) seems to be the most common format, I decided to start with Xml, simply because I know how to parse xml.
Initially, I wanted to use a Ruby library to parse the xml, however I found REXML which comes with Ruby is not yet supported by IronRuby. As such, I had to take a different approach. I decided to use the System.Xml namespace as my base, and then create a wrapper and monkey patch the CLR objects to produce a cleaner more flexible API.
When creating the wrapper, the first task is to define all of the required references. Generally with IronRuby, if you want to do .Net interop you will need to reference mscorlib and System. In this case, I’ve also referenced the System.Xml assembly. The include comment is similar to a using directive in C#, within Ruby include allows you to do ‘Mixins’ and allows the functionality to be accessible from the current module, as if they was combined – a very powerful technique. In this case, it allows us to access CLR objects without needing to specify the namespace.
require 'mscorlib'
require 'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
include System
require 'System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
include System::Xml
The first task is to create a new Ruby class. This class has an initialize method which will take in raw xml as a string. Under the covers, it creates an instance of System.Xml.XmlDocument and loads the xml.
class Document
def initialize(xml)
@document = XmlDocument.new
@document.load_xml xml
end
end
Once we have created the document, we need a way to access the xml elements. Within C#, you would use the SelectNodes method, which returns a XmlNodeList, you would then iterate this collection to access the XmlNodes and as such your data. Well, life in IronRuby is a little different. I found that when iterating over the XmlNodeList, I was getting XmlElement objects, each of the nodes. I also wanted to provide a more ‘ruby-like’ way to access the elements.
The method I created has two arguments, one is the xpath query, the second being a Block, a piece of code which I want to be executed for each element. Within my code, I can iterate over all the elements, passing control back to the block with the element as a parameter for processing.
def elements(xpath, &b)
ele = @document.select_nodes xpath
ele.each do |e|
b.call e
end
end
Within the block, I can place the code required to process that section of the XML. However, I still need a way to access the data of the elements. Because the above code will return XmlElement objects, I wanted to monkey patch the class to include a few custom methods. This is amazingly simple within IronRuby, you define a class with the same name and define your additional methods.
class XmlElement
def get(name)
select_single_node name
end
def to_s
inner_text.to_s
end
end
I also include an additional method called node() which is the same as above, but allows me to return sub-elements from an XmlElement object.
Finally, I saved this in a file called xml.rb. The filename is used by consumers within the require statement.
With this in place, I can use the wrapper to process xml.
# Include the wrapper
require 'xml'
# Create the document
@document = Document.new('<root><name><first>Jim</first><dob><year>1933</year><month>12</month></dob></name><name><first>Bob</first><last>Smith</last></name></root>')
# Access root/name elements
@document.elements('root/name') do |e|
# Output the contents of the element named first
puts e.get('first')
# Access the element named dob, then output the value of year.
e.node('dob') {|y| puts y.get('year')}
end
When I execute this block of code, Jim, 1933, Bob is printed to the console.
>ir processXml.rb
Jim
1933
Bob
While the wrapper isn’t very advanced, it’s a very quick and easy way to start working with xml from IronRuby.
A big thank you to Ivan Porto Carrero who pointed me in the correct direction of how to accept blocks within methods, before I had to do this:
@document.elements('x').collect {|e| puts e.get('first')}
Not much difference, but enough to make a impact.
Feel free to download the wrapper and the sample. For future reference, I've uploaded the code to the MSDN Code Gallery, which I will update if I release a new version.
Labels: IronRuby
OrcsWeb – Creating subdomains using ISAPI Rewrite
Over Christmas I moved my blog over to OrcsWeb. I had been meaning to move hosting provider for a while, however just never got around to it. However, in order to make the move as transparent as possible, I needed to create a subdomain of benhall.me.uk. By default, OrcsWeb does not offer support for subdomains, you can map additional domains onto the account as long as you stay within your account limits, but you can only have one site (In terms of IIS).
However, hats off to the webteam (especially Desirée) at Orcsweb for helping me setup my subdomain, they pointed me towards the direction of ISAPI Rewrite v3 which is setup and ready to go for each site they host. Yesterday, Steve Andrews tweeted about how to do this, so I decided to share the config.
With V3 of ISAPI rewrite, you simply create a file called ‘.htaccess’ in the root of your IIS site. This contains all of your ‘rules’ about how to handle requests.
This is the .htaccess file for my website.
RewriteEngine on
#Redirect rss.xml to feedburner
RewriteCond %{HTTP:Host} blog.benhall.me.uk$
RewriteRule ^(.*)rss\.xml$ http://feeds.feedburner.com/BenHall [R=301,NC]
#Fix missing trailing slash char on folders
RewriteRule ^([^.?]+[^.?/])$ $1/ [R,L]
# this rule directs blog.benhall.me.uk to Sites/blog.benhall.me.uk
RewriteCond %{HTTP:Host} ^(?:blog\.)?benhall\.me\.uk$
RewriteRule ^(.*)$ Sites/blog\.benhall\.me\.uk/$1
The most important section is the last block, this defines that if the request has the HTTP Host address as Blog.BenHall.me.uk, then rewrite the request to return the content from /Sites/blog.benhall.me.uk/ adding additional paths onto the end if required instead.
Now, when you visit blog.benhall.me.uk/index.html, the file is actually returned from /Sites/blog.benhall.me.uk/index.html.
However, for a long time I had a problem in getting this to work as I expected. Because I wanted a seamless experience, I didn’t want /Sites/blog… appearing in the browser’s address bar. It turns out the problem was that in the rule, I was including the full absolute path to the resource, instead of the relative path. By having the IP in the Rule (RewriteRule ^(.*)$ http://0.0.0.0/Sites/blog\.benhall\.me\.uk/$1 ), it was causing a 301 redirect to occur which was being detected by the browser. By having the rule as relative, it would happen under the covers – without the user ever being aware of the change.
Labels: Blogging
Microsoft.Scripting.SyntaxErrorException was unhandled – Unicode support and IronRuby
I just ran head first into a wall I wasn’t expecting. I was attempting to host the DLR within a C# application (topic for another host), the IronRuby code I wanted to load was in an external file and was simply:
def helloWorld()
puts ‘Hello World’
end
However, when I attempted to load the file, I was greeted with an unhandled exception.
Microsoft.Scripting.SyntaxErrorException was unhandled
Message="Invalid character 'ï' in expression"
Source="Microsoft.Scripting"
Column=2
ErrorCode=4112
Line=1
SourceCode="def helloWorld()\r\n puts 'Hello World'\r\nend"
SourcePath="C:/Users/Administrator/Documents/Visual Studio 10/Projects/IronRubyHost/bin/Debug\\helloWorld.rb"
StackTrace:
at Microsoft.Scripting.ErrorSink.Add(SourceUnit source, String message, SourceSpan span, Int32 errorCode, Severity severity) in E:\IronRuby\r156\src\Microsoft.Scripting\ErrorSink.cs:line 34
at Microsoft.Scripting.ErrorCounter.Add(SourceUnit source, String message, SourceSpan span, Int32 errorCode, Severity severity) in E:\IronRuby\r156\src\Microsoft.Scripting\ErrorSink.cs:line 92
at IronRuby.Compiler.Tokenizer.Report(String message, Int32 errorCode, SourceSpan location, Severity severity) in E:\IronRuby\r156\src\ironruby\Compiler\Parser\Tokenizer.cs:line 430
<snip rest of stacktrace – it was boring>
I was surprised to see the additional characters being added to the start of my SourceCode. After a bit of searching, I found this:
http://www.mail-archive.com/ironruby-core@rubyforge.org/msg02137.html
It turns out that Ruby 1.8 (which IronRuby is targeting) doesn’t have support for Unicode characters. When creating a text file using Visual Studio, it automatically saves it with unicode support.
The quickest solution appears to be that you shouldn’t use Visual Studio to create Ruby files – at least until the editor has IronRuby integration. The other solution would be to use another editor, for example GVim or IronEditor, which is shortly going to get a facelift.
Labels: IronRuby
IronRuby with StreamReader and StreamWriter
While playing around with IronRuby, I wanted to access a stream, as such I needed to create a StreamReader. Generally a very simple task, however no matter what I did, I was getting an error message.
The code looked like this, readStream = System::IO::StreamReader.new(receiveStream), however when executed I was always getting the error.
E:\IronRuby\src\IronRuby.Libraries\Builtins\ModuleOps.cs:721:in `const_missing': uninitialized constant System::IO:
:StreamReader (NameError)
NameError means IronRuby cannot find the StreamReader object - a bit of a problem. I thought I had included all the required references, I had access to the System.dll using the correct require statement.
require 'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
After firing up reflector, turns out StreamReader is actually in the mscorlib assembly – not System.dll. This was a simple fix, I added an additional require statement for mscorlib (require 'mscorlib') and I could happily access the StreamReader object.
In future, I’ll remember to always reference mscorlib and system.dll when doing .Net interop – it will just make life easier.
Labels: IronRuby
RubyGems, IronRuby and System::Net namespace
Recently I encountered an interesting gotcha with IronRuby. I wanted to use a rubygem together with the WebRequest CLR object from the System.Net namespace. I had my require and include statements set as shown below.
require 'rubygems'
# Additional require statements
require 'mscorlib'
require 'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
include System
With this in place, I could happily access my gems and CLR objects. However, when I attempt to access WebRequest it failed. The code was correct as I had it working in a different sample.
request = Net::WebRequest.Create(@url)
However, this whenever I tried in the current sample I was getting a NameError, meaning IronRuby was unable to find the class.
E:\IronRuby\src\IronRuby.Libraries\Builtins\ModuleOps.cs:721:in `const_missing': uninitialized constant Net::WebRequest (NameError)
from :0
After a little trial and error, I found that the reason it wasn’t working was because I had included RubyGems, this gave me access to ruby’s standard library. Within the standard library, there is a namespace called Net which has all of the standard objects you would expect for dealing with network communication (net::http, net::telnet etc). As a result, Ruby and .Net clashed with Ruby taking priority, meaning I couldn’t access Net::WebRequest.
The workaround is to be more explicit about what you want. You either need to include the System.Net namespace, include System::Net, or add System when attempting to access the object, System::Net::WebRequest. You will then be able to access the object as normal.
Labels: IronRuby






Social networks
Twitter GitHub SlideShare