October 2009 - Posts

Är du sugen på att vinna ett eget exemplar av Microsoft Arc Mouse?

Det enda du behöver göra för det är att skriva en artikel, en applikation eller spela in en video som handlar om Visual Studio 2010 eller .NET 4.0. Personerna bakom de bästa bidragen belönas med en varsin Arc Mouse!

Tävlingen håller på fram till 22 november och man kan lämna in så många bidrag man vill.

De bästa bidragen kommer även att publiceras på svenska MSDN:s sida för Visual Studio 2010 och .NET 4.0:

http://www.msdn.se/vs2010

För att komma till tävlingen så klicka på länken nedan:

http://www.aspsidan.se

Lycka till!

Precis som rubriken säger så kan man använda HtmlEncode() utan att använda HtmlEncode(), hur logiskt som helst!

I ASP.NET 4.0 så kommer ett nytt kodblock, vilket låter oss göra just det här. Något som man väldigt ofta gör på sina sidor är att skydda sig mot HTML genom att använda HtmlEncode() runt strängen som skall skrivas ut för att bl.a. < skall bli &lt; och > skall bli &gt;. Det nya kodblocket i ASP.NET 4.0 låter oss skippa det här och gör det mycket smidigare att säkra upp sidan mot HTML.

Som exempel så har jag skapat upp ett ASP.NET MVC-projekt i Visual Studio 2010 Beta 2. Jag har inte förändrat något, utan allt är precis som det är från start.

I Index-metoden i HomeController.cs så har vi den gamla vanliga raden:

ViewData["Message"] = "Welcome to ASP.NET MVC!";

Den ser till att ett meddelande skickas till vyn. Väl i vyn så skrivs det ut med HtmlEncode för att se till att inte eventuell HTML skrivs ut:

<h2><%= Html.Encode(ViewData["Message"]) %></h2>

Det vi ska göra nu är att skicka med HTML för att se så att det fungerar som väntat.

Vi skriver om C#-koden tidigare så texten blir kursiv:

ViewData["Message"] = "<i>Welcome to ASP.NET MVC!</i>";

När vi nu ser på sidan så ser vi att texten skrivs ut precis som strängen ser ut, dvs i rent text utan att vara kursiv.

Om vi nu plockar bort Html.Encode() från aspx-filen så blir dock texten kursiv.

Med hjälp av det nya kodblocket så kan vi utan att lägga tillbaka Server.HtmlEncode() ta nytta av funktionen.

Genom att byta ut = mot : i kodblocket så körs HtmlEncode automatiskt på strängen och skriver ut den.

<h2><%: ViewData["Message"] %></h2>

Det är ett mycket renare sätt att lösa det på, då det väldigt ofta händer att man vill köra HtmlEncode.

Det här är en ny funktion i ASP.NET 4.0 och går ej att använda med någon av de tidigare versionerna.

Microsoft släppte för någon timme sedan Visual Studio 2010 Beta 2. Jag hade läst att det skulle komma under dagen så jag satt och slet ut F5-knappen idag. :-)

De olika versioner av Visual Studio 2010 Beta 2 som finns är:

  • Visual Studio 2010 Ultimate Beta 2
  • Visual Studio 2010 Professional Beta 2
  • Visual Studio 2010 Premium Beta 2
  • Visual Studio 2010 Express Combo Beta 2
  • Visual Studio 2010 VWD Express Beta 2
  • Visual Studio 2010 VCS Express Beta 2
  • Visual Studio 2010 VC Express Beta 2
  • Visual Studio 2010 VB Express Beta 2

De tre fetmarkerade är de tre olika versioner av Visual Studio som finns, de övriga är Express-versionerna. Vi kan se några intressanta saker här. Dels så finns det nya namn för Visual Studio – Ultimate, Professional och Premium, dvs precis som för Windows. Sen så har vi även Express Combo som ser ut att vara ett paket med alla Express-versioner.

Jag påbörjade nedladdningen av VS 2010 Ultimate på jobbet, men var tvungen att gå hem, så jag får nog vänta ett tag innan jag får leka ordentligt. :-(

Ni kan dock se fram emot ett antal bloggposter dels här, men även på http://www.msdn.se/vs2010 som är svenska Microsofts sida för Visual Studio 2010 och .NET 4.0.

För information om vad som är nytt i ASP.NET 4.0 Beta 2 så kan ni hitta information här:

http://www.asp.net/learn/whitepapers/aspnet40/

Till nästa gång så koda lugnt! Eller vad tusan.. Koda så det ryker! :-)

Något som är riktigt häftigt är Microsoft Tags. Det är små taggar i form av bilder som man kan använda för att t.ex. göra det enkelt att surfa till en viss URL genom att bara peka mobilkameran mot den. Det kan användas i reklamsyfte, man kan ha det på sitt visitkort för att länka till bloggen eller vad man nu önskar.

Det är svårt att inse hur häftigt det verkligen är förrän man testar det själv!

För att kunna testa det här så surfa med mobiltelefonen till:

http://gettag.mobi/

Det fungerar på de flesta mobiltelefoner, så jag kan rekommendera att ni laddar ned det på direkten. När man startar programmet på mobilen så aktiveras kameran, och när man riktar den mot en bild så startar webbläsaren upp och går till URL:en som bilden är riktad mot.

För att kunna testa att det fungerar så kan ni testa att köra programmet på mobiltelefonen och rikta kameran mot bilden nedan:

1 - blog

Ni bör nu komma till min blogg på mobiltelefonen!

För att kunna skapa taggar som denna själv så kan ni skapa ett konto här:

http://tag.microsoft.com

Det gör det möjligt att skapa upp egna taggar på sidan och generera upp dem i olika färger och typer.

För att kunna ta del av det som finns i artikeln så bör ni även registrera er för API:t, vilket ni kan göra här:

http://www.microsoft.com/tag/content/support/developer/

Ni bör efter ett tag få en API-nyckel skickad till mailen. Den behövs för att ni skall kunna generera taggarna själva.

Skapa egna funktioner för att generera taggar

För att vi ska kunna generera taggarna så har jag en solution i Visual Studio med två klasser, ett klassbibliotek samt ett ASP.NET MVC 2-projekt.

I klassbiblioteket så behöver vi en service-referens till den här URL:en:

https://ws.tag.microsoft.com/MIBPService.wsdl

Vi kommer även att ha en klass vid namn TagRepository där vi lägger till metoderna för att hantera alla taggar.

I den här klassen har vi metoder för att skapa kategorier, skapa taggar och sedan hämta dem.

using MicrosoftTag.TagService;
 
namespace MicrosoftTag
{
    public class TagRepository
    {
        private const string AccessToken = "DIN PRIVATA API-NYCKEL";
 
        UserCredential _credentials;
 
        public TagRepository()
        {
            _credentials = new UserCredential();
            _credentials.AccessToken = AccessToken;
        }
 
        public void CreateTag(string categoryname, URITag tag)
        {
            using (MIBPContractClient client = new MIBPContractClient())
            {
                client.CreateTag(_credentials, categoryname, tag);
            }
        }
 
        public void CreateCategory(Category category)
        {
            using (MIBPContractClient client = new MIBPContractClient())
            {
                client.CreateCategory(_credentials, category);
            }
 
        }
 
        public byte[] GetBarcode(string categoryname, string tagname)
        {
            using (MIBPContractClient client = new MIBPContractClient())
            {
                return client.GetBarcode(
                    _credentials,
                    categoryname,
                    tagname,
                    ImageTypes.gif,
                    0.75F,
                    DecorationType.HCCBRP_DECORATION_NONE,
                    false
                    );
            }
        }
    }
}

Jag kommer inte att gå in så djupgående vad alla anrop gör, utan det är ganska självförklarande. Det som vi eventuellt skulle kunna påverka här är GetBarcode där vi har möjlighet att påverka de taggar som hämtas ut från tjänsten. Vi kan t.ex. välja att ha ett annorlunda utseende på taggen, vi kan välja att ha den i svartvitt, vi kan ändra storlek (0.75-2 inches) m.m. Här har vi den minsta taggen samt har satt att vi inte vill ha någon dekoration runt. Det ger bilden som jag visade tidigare.

Nästa steg blir att skapa ASP.NET MVC 2-projektet. Det här projektet skall ha en referens till klassbiblioteket. Vi måste även kopiera några rader från app.config i klassbiblioteket till web.config i webbprojektet för att webbtjänsten skall hittas.

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="BasicHttpBinding_IMIBPContract" closeTimeout="00:01:00"
                openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
                useDefaultWebProxy="true">
                <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                    maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                <security mode="Transport">
                    <transport clientCredentialType="None" proxyCredentialType="None"
                        realm="" />
                    <message clientCredentialType="UserName" algorithmSuite="Default" />
                </security>
            </binding>
        </basicHttpBinding>
        <customBinding>
            <binding name="BasicHttpBinding_IMIBPContract1">
                <textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
                    messageVersion="Soap11" writeEncoding="utf-8">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                </textMessageEncoding>
                <httpsTransport manualAddressing="false" maxBufferPoolSize="524288"
                    maxReceivedMessageSize="65536" allowCookies="false" authenticationScheme="Anonymous"
                    bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                    keepAliveEnabled="true" maxBufferSize="65536" proxyAuthenticationScheme="Anonymous"
                    realm="" transferMode="Buffered" unsafeConnectionNtlmAuthentication="false"
                    useDefaultWebProxy="true" requireClientCertificate="false" />
            </binding>
        </customBinding>
    </bindings>
    <client>
        <endpoint address="https://ws.tag.microsoft.com/Service.svc"
            binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMIBPContract"
            contract="TagService.IMIBPContract" name="BasicHttpBinding_IMIBPContract" />
    </client>
</system.serviceModel>

För att slippa problem med storleken på bilden som hämtas så kommer vi även att behöva ändra värdet på maxArrayLength under basicHttpBinding\binding\readerQuotas till 16384000. Annars kommer ett lustigt felmeddelande som säger att gränsen har överskridits.

Nästa steg blir att skapa en controller vid namn TagController. Här har vi våra metoder för att kunna skapa kategorier och taggar, samt för att kunna hämta taggarna.

using System.Web.Mvc;
using MicrosoftTag;
using MicrosoftTag.TagService;
 
namespace Web.Controllers
{
    public class TagController : Controller
    {
        TagRepository repository = new TagRepository();
 
        public ActionResult Index()
        {
            return View();
        }
 
        public ActionResult CreateTag()
        {
            return View();
        }
 
        [HttpPost]
        public ActionResult CreateTag(string category, FormCollection collection)
        {
            URITag tag = new URITag();
 
            UpdateModel(tag);
 
            repository.CreateTag(category, tag);
 
            try
            {
                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }
 
        public ActionResult CreateCategory()
        {
            return View();
        }
 
        [HttpPost]
        public ActionResult CreateCategory(FormCollection collection)
        {
            Category category = new Category();
 
            UpdateModel(category);
 
            try
            {
                repository.CreateCategory(category);
 
                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }
 
        public ActionResult GetBarcode()
        {
            return View();
        }
 
        [HttpPost]
        public ActionResult GetBarcode(string category, string tag)
        {
            try
            {
                return File(repository.GetBarcode(category, tag), "image/gif");
            }
            catch
            {
                return View();
            }
        }
    }
}

Våra två formulär har en varsin metod för att ta emot datan och posta till tjänsten. Där kommer sedan kategorier och taggar att lagras. Sedan har vi en metod för att posta namn på kategorin och namnet på taggen för att utifrån det kunna hämta taggarna. Det finns för närvarande ingen metod för att hämta en lista på alla kategorier och taggar, men förhoppningsvis så kommer det i en senare version. Men nu får vi alltså sköta det själva.

Index-sidan kommer att vara en enkel sida som länkar till de olika vyerna för taggar.

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <h2>Administration av tags</h2>
    <p>Använd den här sidan för att administrera dina tags.</p>
    <ul>
        <li><%= Html.ActionLink("Skapa tag", "CreateTag", "Tag") %></li>
        <li><%= Html.ActionLink("Skapa kategori", "CreateCategory", "Tag") %></li>
        <li><%= Html.ActionLink("Hämta tag", "GetBarcode", "Tag") %></li>
    </ul>
</asp:Content>

Sedan kommer vi att behöva ha sidor för de olika formulären. För kategorivyn och taggvyn så genererar vi bara standardsidor för Create som vi binder mot Category och URITag i webbtjänsten. Det hade varit snyggare att ha egna klasser att binda mot, men då det här fungerar snabbt och enkelt så kör vi på det nu.

Om vi nu testar att skapa en kategori så kommer vi att se att den kategorin dyker upp på officiella administrationssidan för Microsoft Tags. Detsamma gäller om vi skapar upp taggar. Vi kan nu alltså enkelt skapa upp taggar som sedan kan användas för att vidarebefordra personer till olika sidor.

Det intressanta sker nu när vi skall skapa sidan för att hämta taggar. Vi börjar med att skapa vyn för formuläret. Det skall inte vara kopplat till någon modell.

Sidan i sin helhet ser ut så här:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <h2>GetBarcode</h2>
    <%= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") %>
    <% using (Html.BeginForm()) {%>
        <fieldset>
            <legend>Fields</legend>
            <p>
                <label for="category">Kategori:</label>
                <%= Html.TextBox("category") %>
                <%= Html.ValidationMessage("category", "*")%>
            </p>
            <p>
                <label for="tag">Namn på tag:</label>
                <%= Html.TextBox("tag") %>
                <%= Html.ValidationMessage("tag", "*") %>
            </p>
            <p>
                <input type="submit" value="Hämta" />
            </p>
        </fieldset>
    <% } %>
    <div>
        <%=Html.ActionLink("Back to List", "Index") %>
    </div>
</asp:Content>

För att testa det så börjar vi med att skapa en kategori vid namn ”Test” och sedan en tagg under den kategorin vid namn ”MSDN” och en URL som pekar mot http://www.msdn.se. När vi väljer att hämta en tagg och fyller i dessa uppgifter så får vi nu:

2 - msdn

Testa gärna att ändra koden så att ni kan få andra utseenden på taggarna. Jag bifogar projektet så att ni enkelt kan få ned det och börja labba själva (ni behöver dock ange en egen API-nyckel):

http://misc.mikaelsoderstrom.se/examples/MicrosoftTag.zip

Kom gärna med egna idéer över hur man kan använda dessa, eller exempel på där de används!

Scott Guthrie gick tidigare idag ut med att Microsoft Ajax Library Preview 6 har släppts. I samband med det så släpptes även Microsoft Ajax Minifier, vilket jag kommer att ta upp nu.

Med Microsoft Ajax Minifier så kan man krympa storleken på sin JavaScript-kod otroligt mycket. Det gör att koden kan laddas in snabbare på sidan och därmed ge en bättre användarupplevelse.

För att komprimera sina js-filer så finns det tre olika sätt, antingen använder man ajaxmin.exe som är ett program som kan anropas genom kommandoprompten, eller så använder man ajaxmintask.dll som kan användas med MSBuild för att komprimera dem vid kompilering, eller ajaxmin.dll som innehåller API:er som kan anropas från vanlig .NET-kod.

Både Microsoft Ajax Library Preview 6 och Microsoft Ajax Minifier går att ladda ned här:

http://aspnet.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=34488

Tyvärr så saknas både ajaxmintask.dll och ajaxmin.dll i nedladdningen ovan i skrivande stund, men det hindrar oss inte från att köra den ändå. :-)

För att kunna anropa från en ASP.NET MVC-applikation så behöver vi först skapa upp en sådan. Vi skapar sedan en CompressControler och en vy för visning av dels formuläret och dels JavaScriptet som är komprimerat.

Sedan gör vi ett litet fulhack då dll:en inte finns, vi skapar en referens till ajaxmin.exe istället då den innehåller alla API:er som vi behöver.

Jag har även skapat en enkel model som kommer att användas i exemplet.

namespace JsCompress.Models
{
    public class JavaScript
    {
        public string OriginalJavaScript { get; set; }
        public string CompressedJavaScript { get; set; }
    }
}

Den innehåller originalversionen av JavaScriptet och den komprimerade versionen. Jag kommer inte att göra något med dessa förutom att skriva ut den komprimerade, men det skulle t.ex. kunna cachas för att snabbt kunna komprimeras på servern och laddas in på sidan.

Den fullständiga controllern ser ut så här:

using System.Web.Mvc;
using JsCompress.Models;
using Microsoft.Ajax.Utilities;
 
namespace JsCompress.Controllers
{
    public class CompressController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }
 
        [AcceptVerbs(HttpVerbs.Post)]
        [ValidateInput(false)]
        public ContentResult Index(FormCollection collection)
        {
            JavaScript js = new JavaScript();
 
            UpdateModel(js);
 
            JSParser parser = new JSParser(js.OriginalJavaScript, null);
            Block block = parser.Parse(new CodeSettings());
            js.CompressedJavaScript = block.ToCode();
 
            return Content(js.CompressedJavaScript, "text/plain");
        }
    }
}

Det jag gör vid postning är att skapa en ny instans av JSParser, vilket kommer från exe-filen. Där skickar jag med originalversionen av JavaScriptet, vilket kommer med i postningen. Sedan parseas JavaScriptet och sparas i CompressedJavaScript.

Det sista som sker är att det skrivs ut på sidan som text/plain genom en ContentResult.

Det finns många inställningar för hur parsningen skall ske, så jag rekommenderar att ni läser igenom dokumentationen vilken följer med i nedladdningen.

Index-vyn i CompressController har bara ett enkelt fält:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<JsCompress.Models.JavaScript>" %>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <h2>Komprimera JavaScript</h2>
    <% using (Html.BeginForm()) {%>
        <fieldset>
            <legend>Komprimera ett JavaScript</legend>
            <p>
                <label for="OriginalJavaScript">JavaScript:</label>
                <%= Html.TextArea("OriginalJavaScript", new { cols = "120", rows = "20" })%>
            </p>
            <p>
                <input type="submit" value="Compress" />
            </p>
        </fieldset>
    <% } %>
</asp:Content>

För att testa hur det fungerar så kommer jag att använda ett JavaScript som ser ut så här:

//En funktion som räknar ut x + y
function Sum(x, y) {
    return x + y;
}
 
alert(Sum(1, 2));

Om vi testar att stoppa in den i textrutan och väljer att komprimera så får vi nu upp det här:

function Sum(x,y){return x+y}alert(Sum(1,2))

Alla onödiga mellanslag och kommentarer har plockats bort, vilket gör att scriptet nu tar mindre plats.

Det kan antingen användas innan produktionssättning och sedan laddas upp, eller så kan ni modifiera det så att den genererar en kompilerad version direkt på servern varje gång filen uppdateras.

Projektet med exemplen finns att ladda ned här:

http://misc.mikaelsoderstrom.se/examples/jscompress.zip

Något som är väldigt vanligt på webbsidor (speciellt i CMS) är att man vill ha en Wysiwyg-editor på sidan för att enkelt kunna redigera sidorna och låta redaktörerna anpassa utseendet på texten samt lägga in bilder och annat.

När man vill lägga in en sådan så kan man ladda ned den och lägga in den på de ställen där det passar. Det kan dock krävas en del jobb, samtidigt som man kan behöva lägga in den på flera ställen. Dessutom så finns det en risk för att det kan bli onödigt mycket jobb för att vara säker på att den fortfarande fungerar om den byts ut.

Så hur kan man lösa det här på ett enkelt sätt?

UIHint används som bekant av både ASP.NET Dynamic Data och ASP.NET MVC 2 för att anpassa hur olika egenskaper skrivs ut på sidan. Man kan genom att ändra i en user control enkelt byta ut kontroller och vara säker på att de fortfarande fungerar. Jag kommer att gå igenom hur vi kan använda detta för att enkelt få till en Wysiwyg-editor istället för vanliga text-fält.

Först och främst så skall vi använda oss utav en modell kallad ”Customer” (surprise!). Den kommer att ha två egenskaper, ett id för att identifiera den aktuella kunden och sedan ”Information”, vilket kommer att vara en sträng med HTML där vi har information om kunden.

namespace Wysiwyg.Models
{
    public partial class Customer
    {
        public int Id { get; set; }
        public string Information { get; set; }
    }
}

Vi kommer även att ha en CustomerController. Vid skapandet väljer vi att få med de extra metoderna för att skapa, editera och ta bort. Vi har även med en metod här som används för att fylla på med lite dummy-data.

public List<Customer> GetCustomers()
{
    return new List<Customer>() {
        new Customer() {
            Id = 1,
            Information = "Hej 1"
        },
        new Customer() {
            Id = 2,
            Information = "Hej 2"
        },
        new Customer() {
            Id = 3,
            Information = "Hej 3"
        }
    };
}

Om vi nu skapar upp en Index-sida och en Edit-sida som vi fyller med informationen från GetCustomers() så kommer vi att kunna se informationen om dem och få möjligheten att få upp ett redigeringsformulär.

Formuläret ser dock rätt tråkigt ut i dess standardutförande:

1 - Form

Det vi vill ha istället för en enkel textruta är en Wysiwyg-editor där man skall kunna använda HTML för att snygga till texten.

Vi börjar med att skapa upp en EditorTemplate för det. Det gör vi genom att skapa upp en ASP.NET MVC User Control vid namn Wysiwyg.ascx och som vi lägger i Views\Shared\EditorTemplates. Vill vi ha en template för vanlig visning så lägger vi istället våra user controls i en mapp kallad DisplayTemplates.

Den nyskapade filen kommer att ha det här innehållet:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<string>" %>
<%= Html.TextArea("Information", Model }) %>

Vi behöver även lägga till ett attribut på Information-fältet i en metadata-klass. Skapa upp en ny partiell klass till Customer som ser ut i stil med det här:

using System.ComponentModel.DataAnnotations;
 
namespace Wysiwyg.Models
{
    [MetadataType(typeof(Customer_Metadata))]
    public partial class Customer
    {
        class Customer_Metadata
        {
            [UIHint("Wysiwyg")]
            public string Information { get; set; }
        }
    }
}

Går vi in på sidan nu så kommer vi istället att ha en text-area, vilket är en bra början. Vi kan nu lägga till text på flera rader, men vi har fortfarande inget Wysiwyg-läge, så hur får vi dit det?

Först och främst så laddar vi ned CKEditor 3.0 (det hette tidigare FCKEditor, men bytte namn då det är alldeles för likt ett ord som också innehåller bokstäverna FCK ;-)). Det hittar vi här:

http://ckeditor.com

När det är nedladdat så lägger vi ckeditor-mappen i roten för får webbapplikation.

Nu behöver vi ändra lite i vår EditorTemplate för att få fram CKEditor istället för vår TextArea. Jag kommer att använda exempel-filerna som finns med i CKEditor, men ni kan lika gärna skapa egna för att kunna anpassa utseendet mer. För mer information om vad som går att göra så rekommenderar jag att ni kollar igenom exemplen som följer med, samt kollar igenom dokumentationen som finns på CKEditors hemsida.

Den modifierade versionen av Wysiwyg.ascx ser ut så här:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<string>" %>
<script src="/ckeditor/ckeditor.js" type="text/javascript"></script>
<script src="/ckeditor/_samples/sample.js" type="text/javascript"></script>
<link href="/ckeditor/_samples/sample.css" rel="stylesheet" type="text/css" />
<%= Html.TextArea("Information", Model, new { @class = "ckeditor" }) %>

Jag har två referenser till js-filer och en till en css-fil här. Jag har även satt klassen för textarean till ”ckeditor”.

Om vi nu kollar på sidan igen så kommer vi att se en stor förändring:

2 - Wysiwyg

Genom att sätta [UIHint(”Wysiwyg”)] på valfritt fält i någon klass så kan vi alltså få in en Wysiwyg-editor direkt på sidan utan något strul alls.

Om vi postar formuläret nu så kommer vi dock att få ett felmeddelande på grund av ValidateRequest i ASP.NET. För att slippa detta så måste vi sätta ValidateInput till false på de controllers som man skall kunna posta HTML till. Det här är för att vara säker på att ingen postar HTML där det inte är meningen att man ska kunna göra det.

[AcceptVerbs(HttpVerbs.Post)]
[ValidateInput(false)]
public ActionResult Edit(int id, FormCollection collection)

När det här är gjort så kommer vi att kunna använda vår Wysiwyg-editor som om det vore vilken kontroll som helst på sidan.

Vem har sagt att programmering är svårt? :-)

Exemplet i artikeln finns att ladda ned här:

http://misc.mikaelsoderstrom.se/examples/wysiwyg.zip

Jag har tidigare nämnt att det som finns i ASP.NET MVC 2 Preview 2 (och Preview 1 förstås) är något som är långt ifrån färdigt, och mycket väl kan fungera helt annorlunda när det väl är släppt. Ser man på ASP.NET MVC 1 så var det enorm skillnad på de första preview-versionerna jämfört med den färdiga produkten.

Men finns det något roligare än att labba med preview-versionerna av ASP.NET MVC? Japp! Man kan även labba med ASP.NET MVC Futures. :-)

ASP.NET MVC Futures är ett paket med funktioner som inte har kommit till det stadiet där det kan användas i preview-versionerna. Det beror på att de mest används för att testa nya funktioner, som eventuellt kan hamna i en preview och därefter möjligtvis kan hamna i den färdiga produkten. Det har även släppts några ASP.NET Futures för vanliga ASP.NET, där vissa funktioner kommer med, andra inte.

Innan jag går vidare så rekommenderar jag att du laddar ned ASP.NET MVC Futures, vilket du hittar här:

http://aspnet.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=33836

Det ni behöver är både ASP.NET MVC 2 Preview 2, och ASP.NET MVC Futures Assembly for Preview 2.

Sätt upp projektet

När det är nedladdat så skapa ett ASP.NET MVC 2-projekt. Här lägger vi till en klass i models-mappen som ser ut på detta vis:

public class Customer
{
    [DisplayName("Kund-ID")]
    public int CustomerId { get; set; }
 
    [Required(ErrorMessage = "Du måste ange ett förnamn!")]
    public string FirstName { get; set; }
 
    [Required(ErrorMessage = "Du måste ange ett förnamn!")]
    public string LastName { get; set; }
 
    [Required(ErrorMessage="Du måste ange ett födelsedatum")]
    public DateTime Birthday { get; set; }
}

Vi kommer även att skapa en CustomerController, där vi lägger till den här metoden på slutet för att få lite dummy-data:

public List<Customer> GetCustomers()
{
    List<Customer> customers = new List<Customer>();
 
    customers.Add(new Customer()
    {
        CustomerId = 1,
        FirstName = "Sven",
        LastName = "Svensson",
        Birthday = new DateTime(1900, 01, 01)
    });
 
    customers.Add(new Customer()
    {
        CustomerId = 2,
        FirstName = "Nils",
        LastName = "Nilsson",
        Birthday = new DateTime(1948, 10, 22)
    });
 
    customers.Add(new Customer()
    {
        CustomerId = 3,
        FirstName = "Petter",
        LastName = "Pettersson",
        Birthday = new DateTime(1940, 05, 12)
    });
    return customers;
}

Vi ser även till att vi får vår lista till Index-metoden:

return View(GetCustomers());

Skapa sedan en Index-view som är hårt typad till Customer och som ska lista kunder.

För att få en länk till den här sidan så lägger vi även till det här i master-sidan:

<li><%= Html.ActionLink("Customers", "Index", "Customer")%></li>

Det vi har nu är en helt vanlig ASP.NET MVC 2-sida med möjlighet att lista kunder. Om något verkar oklart så rekommenderar jag att du läser mina introduktionsartiklar till ASP.NET MVC innan du fortsätter.

Webbkontroller för ASP.NET MVC

Japp, det är sant. Webbkontroller kommer (eventuellt) till ASP.NET MVC, precis som de fanns för ASP.NET Web Forms. Min första tanke var något i stil med ”WTF!? OMFG!!!”, men efter att ha testat lite så verkar det inte alltför dumt då det gör det enklare att introducera ASP.NET Web Forms-utvecklare till ASP.NET MVC.

För att kunna använda webbkontrollerna så börjar vi med att lägga till den här raden i web.config under configuration/system.web/pages/controls:

<add tagPrefix="mvc" namespace="Microsoft.Web.Mvc.Controls" assembly="Microsoft.Web.Mvc" />

Det här gör att vi slipper skapa referenser till assemblyn på varje sida där vi använder kontrollerna, vilket gör aspx-filerna lite renare. Anledningen till att jag har satt ”mvc” som prefix är för att det annars kan krocka med den vanliga webbkontrollerna.

Vi kan även lägga till kontrollerna i toolboxen i Visual Studio. Det gör vi genom att högerklicka i toolboxen, välja ”Choose Items…” och sedan bläddra fram till Microsoft.Web.Mvc. När vi väljer den assemblyn så får vi automatiskt alla kontroller som finns i den.

Vi har nu det här i vår toolbox:

1 - Toolbox

Det finns alltså kontroller för de funktioner som vi använder oftast i vår applikation. Jag kommer att gå igenom dessa en för en, för att visa hur det fungerar.

Webbkontroller

ActionLink

Den första kontrollen vi har är en ActionLink, vilken gör exakt vad det låter som. För att använda den på vår sida så öppnar vi först upp master-sidan. Sedan byter vi ut vår customer-länk som nu ser ut så här:

<li><%= Html.ActionLink("Customers", "Index", "Customer")%></li>

Mot:

<li><mvc:ActionLink runat="server" ActionName="Index" ControllerName="Customer" Text="Customers" /></li>

Det är alltså en webbkontroll som använder properties för att ange action, controller och texten som skall synas.

Något som är väldigt positivt här är att det inte renderas någon hemsk HTML i stil med Web Forms, utan det som kommer är ett vanligt a-element precis som för Html.ActionLink(). Kontrollen kan ses som en Html.ActionLink(), men utan kodblocken runt.

DropDownList

DropDownList-kontrollen returnerar en enkel select-lista på sidan. Då ASP.NET MVC inte har stöd för PostBacks så finns ingen möjlighet att använda AutoPostBack på kontrollen, utan sådant får man sköta med egna JavaScript om man så önskar.

För att använda kontrollen så lägger vi först in kontrollen på index-sidan:

<mvc:DropDownList runat="server" Name="customers" />

För att kunna fylla den med data så måste vi använda ViewData[”customers”] och fylla den med en IEnumerable<SelectListItem>. Då fylls vår DropDownList med datan som finns i ViewData-objektet.

Koden vi använder i controllern för att fylla listan med namnen på alla personer är:

List<SelectListItem> customers = new List<SelectListItem>();
 
foreach (Customer customer in GetCustomers())
{
    customers.Add(new SelectListItem()
    {
        Text = customer.FirstName + " " + customer.LastName
    });
}
 
ViewData["customers"] = customers;

När vi sedan kör sidan så får vi upp en enkel lista med alla namn:

2 - Dropdownlist

Hidden

Det händer ofta att man vill ha med dolda input-fält på klienten som sedan skall följa med när man postar.

När man använder kontrollen så ser det ut så här:

<mvc:Hidden runat="server" Format="hemlis" Name="hiddenfield" />

Det renderas så här:

<input name="hiddenfield" type="hidden" value="hemlis" />

Format är alltså värdet vi vill skicka med och Name just namnet som sedan används när man ska plocka fram värdet vid en postning.

Label

En ganska användbar kontroll är Label-kontrollen. Det som renderas är ren text, ungefär som Literal-kontrollen för Web Forms. Den har dock vissa funktioner för att kapa texten efter en viss längd, vilket kan vara användbart när man t.ex. skriver ut kortfattade nyheter på startsidan och sedan vill länka till den fullständiga nyheten.

När man använder den med alla dess properties så ser den ut så här:

<mvc:Label
    runat="server"
    Name="lbl"
    EncodeType="Html"
    Format="En label med en massa text. Den kapas efter 15 tecken."
    TruncateLength="15"
    TruncateText="..."
    Visible="true"
    />

Name måste anges trots att den inte används.

EncodeType kan sättas till None, Html och HtmlAttribute, där den Html och HtmlAttribute kör HtmlEncode på texten.

Format är själva texten som skall skrivas ut.

TruncateLength avgör hur många tecken som ska visas.

TruncateText visar vilken text som skall visas efter att den inmatade texten har klippts. HtmlEncode körs aldrig på denna.

Visible är en boolean och kan sättas till false om man inte vill att texten skall visas.

Password

Password-kontrollen renderar ett vanligt lösenordsfält.

Den används på det här sättet:

<mvc:Password Name="pwd" runat="server" />

Det som matas in blir automatiskt dolt för användaren.

TextBox

TextBox-kontrollen renderar en vanlig textruta på sidan.

<mvc:TextBox
    runat="server"
    Format="Text..."
    Name="textruta"
    Visible="true"
    />

Format innehåller standardvärdet för kontrollen och visible avgör om den skall visas eller ej.

Repeater

En av de mest intressanta kontrollerna är repeater-kontrollen. När man arbetar med ASP.NET MVC och har foreach-loopar i kodblock direkt i koden så kan det lätt bli rörigt. Det kan Repeater-kontrollen lösa snyggt.

Den kan användas så här:

<mvc:Repeater runat="server" Name="rptcustomers">
    <EmptyDataTemplate>
    <li>Ingen data...</li>
    </EmptyDataTemplate>
    <ItemTemplate>
    <li>
        <%#Eval("FirstName") %>
    </li>
    </ItemTemplate>
</mvc:Repeater>

Om vi kör sidan nu så ser vi bara texten ”Ingen data…”, vilket beror på att vi ännu inte har skickat med någon data till kontrollen.

För att fylla repeater-kontrollen med data så lägger vi till det här i controllern:

ViewData["rptcustomers"] = GetCustomers();

Det som sker nu är att vi har bundit vår List<Customer> till Repeater-kontrollen, vilket gör att vi kommer åt alla element genom Eval(”property”).

Gör dina vyer Rest-baserade

Något som är riktigt häftigt och som följer med i ASP.NET MVC 2 Futures är möjligheten att använda sina vyer för rest-baserade anrop. Vi kan på ett väldigt enkelt sätt göra det möjligt att returnera XML eller Json istället för de vanliga HTML-baserade vyerna.

För att göra det här möjligt så lägger vi till de här raderna i Application_Start() i global.asax:

ResourceControllerFactory factory = new ResourceControllerFactory();
ModelBinders.Binders.DefaultBinder = new ResourceModelBinder();
 
ControllerBuilder.Current.SetControllerFactory(factory);

När vi sedan vill göra det möjligt att använda Rest för en vy så lägger vi till WebApiEnabled-attributet på de metoder i våra controllers där vi vill ha det.

Exempel:

[WebApiEnabled]
public ActionResult Index()

Om vi nu surfar till /Customer?format=xml så får vi det här:

3 - XML

Vi kan även ange format=json för att få det som Json, vilket underlättar om vi kör med Ajax för att rendera data.

Det här gör det riktigt smidigt att kunna använda Rest för att kunna hantera datan på sidan.

Om vi har tur så kommer det här till ASP.NET MVC 2!

ViewState i ASP.NET MVC? WTF?

Något som gör att många föredrar ASP.NET MVC framför ASP.NET Web Forms är just det att man inte har någon ViewState. I ASP.NET MVC Futures så kan vi dock hitta detta. Det är inte riktigt samma sak som i Web Forms, utan vi får istället möjlighet att påverka den helt, och vi behöver inte använda den om vi inte vill.

För att testa detta så skapar vi en Edit-sida för våra customers.

Under raden med ”using (Html.BeginForm())” så lägger vi till det här:

<%= Html.Serialize("customer", Model) %>

När vi sedan kollar i den renderade HTML-koden så ser vi det här:

<input name="customer" type="hidden" value="/wEykAIAAQAAAP////8BAAAAAAAAAAwCAAAAPkZ1dHVyZXMsIFZlcnNpb249MS4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsBQEAAAAXRnV0dXJlcy5Nb2RlbHMuQ3VzdG9tZXIEAAAAGzxDdXN0b21lcklkPmtfX0JhY2tpbmdGaWVsZBo8Rmlyc3ROYW1lPmtfX0JhY2tpbmdGaWVsZBk8TGFzdE5hbWU+a19fQmFja2luZ0ZpZWxkGTxCaXJ0aGRheT5rX19CYWNraW5nRmllbGQAAQEACA0CAAAAAQAAAAYDAAAABFN2ZW4GBAAAAAhTdmVuc3NvbgBAVyBTBVEICw==" />

Det som lagras är den aktuella typen som modellen använder. Det kan sedan användas när man postar formuläret, vilket gör att vi kan skippa vissa fält i formuläret och bara ta med det vi vill.

Det finns även en tredje parameter till Serialize-metoden som vi kan använda om vi vill, nämligen en av typen SerializationMode. Det är en enum med fyra fält, Encrypted, EncryptedAndSigned, PlainText och Signed. Standard är PlainText, vilket returnerar en Base64-kodad sträng.

Det här är något som finns med, men som absolut inte behöver användas. Vi kan lika väl dölja denna.

När vi tar emot postningen i en controller så måste vi sedan ha med en parameter av typen Customer och som har Deserialize-attributet. Då får vi automatiskt med alla ordinare värden, även om vi bara har ett fält för namnet i formuläret.

Det är upp till var och en om man vill använda serialisering eller inte. Fördelen är att man inte behöver fält för värden man inte bryr sig om, nackdelen är att html-koden blir fulare.

Det finns även en del annat intressant i ASP.NET MVC Futures, men det här är de delar som jag ser som mest intressanta i nuläget.

Jag har sedan länge använt betaversionen av Microsoft My Phone, vilket har fungerat utmärkt på min mobil.

För er som inte har använt det så är det ett program som gör det möjligt att synkronisera mobiltelefonen eller mobiltelefonerna om du har fler, så att du alltid har tillgång till alla bilder, all musik, alla videos, dina SMS och mycket annat. Allt lagras i molnet, så om din mobil går sönder, om du blir av med den eller om du bara har köpt en ny så kan du på ett väldigt enkelt sätt återställa allt på den nya.

När man har laddat upp allt så går det att komma åt innehållet på hemsidan för My Phone, vilket gör att man kan se sina bilder, läsa SMS och annat utan att behöva ha telefonen på sig.

Nu har – i samband med släppet av Windows Phones (telefoner med Windows Mobile 6.5) – My Phone gått ur betastadiet och släppts skarpt.

Nya funktioner som finns med den skarpa versionen är:

Dela foton via sociala nätverk.

Hitta en borttappad telefon.

Premiumtjänster som att låsa telefonen, skicka ett meddelande till telefonen eller helt enkelt rensa den på allt innehåll, direkt via hemsidan. Premiumtjänsterna är gratis ett tag framöver, så se till att testa dem under tiden!

Har du en mobiltelefon med Windows Mobile? Då bör du definitivt testa det på en gång!

Mer information finns här:

http://myphone.microsoft.com

När man arbetar med dynamic i .NET 4.0 så tar man ett befintligt objekt och säger att man vill använda vissa metoder eller egenskaper som finns för det objektet. Det laddas anropas sedan under runtime. Om objektet inte har de metoder som finns så får man under runtime ett fel om det, trots att allt kompilerade utan problem.

Så hur gör vi nu om vi vill skapa ett dynamiskt objekt och berätta för det vilka egenskaper och värden som finns samt till dela dem värden för att sedan anropa dem?

I .NET 4.0 under System.Dynamic så finns det ett objekt för detta, kallat ExpandoObject. Det är ett helt tomt objekt utan några egenskaper eller metoder som helst förutom de vanliga Equals(), GetHashCode(), GetType() och ToString(). Det implementerar dock ett antal interfaces, vilka används internt för att hålla reda på de metoder vi lägger på det dynamiska objektet: IDynamicMetaObjectProvider, IDictionary<string, Object>, ICollection<KeyValuePair<string, Object>>, IEnumerable<KeyValuePair<string, Object>> och IEnumerable.

När vi använder ExpandoObject så kan vi skapa instansen som vanligt:

ExpandoObject o = new ExpandoObject(); 

Det här gör dock att vi star där med en instans av ett object som inte kan göra något förutom att visa att det är ett ExpandoObject, ingen höjdare alltså.

Vi kan däremot skapa en dynamisk instans av detta objekt, och då lägga på några metoder.

dynamic magic = new ExpandoObject();
 
magic.IntX = 10;
magic.IntY = 20;
magic.Name = "Nisse";
magic.SayHello = new Action<string>(x => Console.WriteLine("Hello, " + x + "!"));
magic.Multiply = new Func<int, int, int>((x, y) => x * y);

Här har vi skapat en dynamisk instans av ett ExpandoObject, och säger att vi har ett antal metoder och egenskaper som ska finnas på det objektet.

Om det här hade varit en instans av ett vanligt objekt så hade vi fått ett runtime-fel som sager att metoderna inte finns för objektet. Det naturliga vore om detsamma gäller för detta objekt, så vi lägger till de här raderna under:

Console.WriteLine("X: {0}", magic.IntX);
Console.WriteLine("Y: {0}", magic.IntY);
Console.WriteLine("Name: {0}", magic.Name);
Console.WriteLine("Multiply(X, Y): {0}", magic.Multiply(magic.IntX, magic.IntY));
magic.SayHello(magic.Name);

När vi nu startar igång programmet så ser vi att vi inte alls fick något fel, utan istället det här:

1 - Console

Vi har alltså skapat upp ett dynamiskt objekt och tilldelat det metoder och egenskaper, på precis samma sätt som vi hade gjort med ett dynamiskt språk som JavaScript eller IronRuby, trots att det är ett statiskt språk vi arbetar med!

Så hur går det till? Som jag nämnde tidigare så implementerar ExpandoObject ett antal interfaces som används för collections. När vi tilldelar vårt objekt egenskaper med dess värden så lagras dessa i collections internt i objektet, och plockas sedan fram när vi anropar dem.

Om vi debuggar så ser vi att vi får upp detta:

2 - Debug Dynamic View

I Visual Studio 2010 så finns det en ny visualizer som används för att visa vad som finns i dynamiska vyer som denna. Vi kan här se att det har skapats olika metoder för vårt objekt med antingen datan vi har skickat in, eller de delegater som används (Action<string> och Func<int, int, int>).

Om vi går ännu djupare så kan vi se att det i vårt objekt finns en Dictionary<string, object> som håller reda på våra objekt:

3 - Dictionary

Vi kan enkelt se alla nycklar:

4 - Keys

Och värden:

5 - Values

Om vi analyserar IL-koden så kan vi se att Action<> och Func<> har skrivits om till vanliga void.

SayHello:

.method private hidebysig static void <Main>b__12(string x) cil managed
{
    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
    .maxstack 8
    L_0000: ldstr "Hello, "
    L_0005: ldarg.0 
    L_0006: ldstr "!"
    L_000b: call string [mscorlib]System.String::Concat(string, string, string)
    L_0010: call void [mscorlib]System.Console::WriteLine(string)
    L_0015: nop 
    L_0016: ret 
}
 
.field private static class [mscorlib]System.Action`1<string> CS$<>9__CachedAnonymousMethodDelegate14
{
    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
}

Multiply:

.method private hidebysig static int32 <Main>b__13(int32 x, int32 y) cil managed
{
    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
    .maxstack 2
    .locals init (
        [0] int32 CS$1$0000)
    L_0000: ldarg.0 
    L_0001: ldarg.1 
    L_0002: mul 
    L_0003: stloc.0 
    L_0004: br.s L_0006
    L_0006: ldloc.0 
    L_0007: ret 
}
 
.field private static class [mscorlib]System.Func`3<int32, int32, int32> CS$<>9__CachedAnonymousMethodDelegate15
{
    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
}

Det är inga konstigheter här, utan vid kompilering så sker detta alltid automatiskt.

Därememot så är Main-metoden mer intressant.

.method private hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 15
    .locals init (
        [0] object magic,
        [1] class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[] CS$0$0000)
    L_0000: nop 
    L_0001: newobj instance void [System.Core]System.Dynamic.ExpandoObject::.ctor()
    L_0006: stloc.0 
    L_0007: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site1
    L_000c: brtrue.s L_004a
    L_000e: ldstr "IntX"
    L_0013: ldtoken ExpandoObjectTesting.Program
    L_0018: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_001d: ldc.i4.2 
    L_001e: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_0023: stloc.1 
    L_0024: ldloc.1 
    L_0025: ldc.i4.0 
    L_0026: ldc.i4.0 
    L_0027: ldnull 
    L_0028: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_002d: stelem.ref 
    L_002e: ldloc.1 
    L_002f: ldc.i4.1 
    L_0030: ldc.i4.3 
    L_0031: ldnull 
    L_0032: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_0037: stelem.ref 
    L_0038: ldloc.1 
    L_0039: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpSetMemberBinder::.ctor(string, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
    L_003e: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32, object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_0043: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site1
    L_0048: br.s L_004a
    L_004a: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site1
    L_004f: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32, object>>::Target
    L_0054: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site1
    L_0059: ldloc.0 
    L_005a: ldc.i4.s 10
    L_005c: callvirt instance !3 [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32, object>::Invoke(!0, !1, !2)
    L_0061: pop 
    L_0062: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site2
    L_0067: brtrue.s L_00a5
    L_0069: ldstr "IntY"
    L_006e: ldtoken ExpandoObjectTesting.Program
    L_0073: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_0078: ldc.i4.2 
    L_0079: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_007e: stloc.1 
    L_007f: ldloc.1 
    L_0080: ldc.i4.0 
    L_0081: ldc.i4.0 
    L_0082: ldnull 
    L_0083: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_0088: stelem.ref 
    L_0089: ldloc.1 
    L_008a: ldc.i4.1 
    L_008b: ldc.i4.3 
    L_008c: ldnull 
    L_008d: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_0092: stelem.ref 
    L_0093: ldloc.1 
    L_0094: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpSetMemberBinder::.ctor(string, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
    L_0099: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32, object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_009e: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site2
    L_00a3: br.s L_00a5
    L_00a5: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site2
    L_00aa: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32, object>>::Target
    L_00af: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site2
    L_00b4: ldloc.0 
    L_00b5: ldc.i4.s 20
    L_00b7: callvirt instance !3 [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32, object>::Invoke(!0, !1, !2)
    L_00bc: pop 
    L_00bd: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, string, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site3
    L_00c2: brtrue.s L_0100
    L_00c4: ldstr "Name"
    L_00c9: ldtoken ExpandoObjectTesting.Program
    L_00ce: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_00d3: ldc.i4.2 
    L_00d4: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_00d9: stloc.1 
    L_00da: ldloc.1 
    L_00db: ldc.i4.0 
    L_00dc: ldc.i4.0 
    L_00dd: ldnull 
    L_00de: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_00e3: stelem.ref 
    L_00e4: ldloc.1 
    L_00e5: ldc.i4.1 
    L_00e6: ldc.i4.3 
    L_00e7: ldnull 
    L_00e8: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_00ed: stelem.ref 
    L_00ee: ldloc.1 
    L_00ef: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpSetMemberBinder::.ctor(string, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
    L_00f4: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, string, object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_00f9: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, string, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site3
    L_00fe: br.s L_0100
    L_0100: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, string, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site3
    L_0105: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, string, object>>::Target
    L_010a: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, string, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site3
    L_010f: ldloc.0 
    L_0110: ldstr "Nisse"
    L_0115: callvirt instance !3 [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, string, object>::Invoke(!0, !1, !2)
    L_011a: pop 
    L_011b: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, class [mscorlib]System.Action`1<string>, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site4
    L_0120: brtrue.s L_015e
    L_0122: ldstr "SayHello"
    L_0127: ldtoken ExpandoObjectTesting.Program
    L_012c: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_0131: ldc.i4.2 
    L_0132: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_0137: stloc.1 
    L_0138: ldloc.1 
    L_0139: ldc.i4.0 
    L_013a: ldc.i4.0 
    L_013b: ldnull 
    L_013c: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_0141: stelem.ref 
    L_0142: ldloc.1 
    L_0143: ldc.i4.1 
    L_0144: ldc.i4.1 
    L_0145: ldnull 
    L_0146: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_014b: stelem.ref 
    L_014c: ldloc.1 
    L_014d: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpSetMemberBinder::.ctor(string, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
    L_0152: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, class [mscorlib]System.Action`1<string>, object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_0157: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, class [mscorlib]System.Action`1<string>, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site4
    L_015c: br.s L_015e
    L_015e: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, class [mscorlib]System.Action`1<string>, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site4
    L_0163: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, class [mscorlib]System.Action`1<string>, object>>::Target
    L_0168: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, class [mscorlib]System.Action`1<string>, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site4
    L_016d: ldloc.0 
    L_016e: ldsfld class [mscorlib]System.Action`1<string> ExpandoObjectTesting.Program::CS$<>9__CachedAnonymousMethodDelegate14
    L_0173: brtrue.s L_0188
    L_0175: ldnull 
    L_0176: ldftn void ExpandoObjectTesting.Program::<Main>b__12(string)
    L_017c: newobj instance void [mscorlib]System.Action`1<string>::.ctor(object, native int)
    L_0181: stsfld class [mscorlib]System.Action`1<string> ExpandoObjectTesting.Program::CS$<>9__CachedAnonymousMethodDelegate14
    L_0186: br.s L_0188
    L_0188: ldsfld class [mscorlib]System.Action`1<string> ExpandoObjectTesting.Program::CS$<>9__CachedAnonymousMethodDelegate14
    L_018d: callvirt instance !3 [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, class [mscorlib]System.Action`1<string>, object>::Invoke(!0, !1, !2)
    L_0192: pop 
    L_0193: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, class [mscorlib]System.Func`3<int32, int32, int32>, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site5
    L_0198: brtrue.s L_01d6
    L_019a: ldstr "Multiply"
    L_019f: ldtoken ExpandoObjectTesting.Program
    L_01a4: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_01a9: ldc.i4.2 
    L_01aa: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_01af: stloc.1 
    L_01b0: ldloc.1 
    L_01b1: ldc.i4.0 
    L_01b2: ldc.i4.0 
    L_01b3: ldnull 
    L_01b4: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_01b9: stelem.ref 
    L_01ba: ldloc.1 
    L_01bb: ldc.i4.1 
    L_01bc: ldc.i4.1 
    L_01bd: ldnull 
    L_01be: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_01c3: stelem.ref 
    L_01c4: ldloc.1 
    L_01c5: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpSetMemberBinder::.ctor(string, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
    L_01ca: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, class [mscorlib]System.Func`3<int32, int32, int32>, object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_01cf: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, class [mscorlib]System.Func`3<int32, int32, int32>, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site5
    L_01d4: br.s L_01d6
    L_01d6: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, class [mscorlib]System.Func`3<int32, int32, int32>, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site5
    L_01db: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, class [mscorlib]System.Func`3<int32, int32, int32>, object>>::Target
    L_01e0: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, class [mscorlib]System.Func`3<int32, int32, int32>, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site5
    L_01e5: ldloc.0 
    L_01e6: ldsfld class [mscorlib]System.Func`3<int32, int32, int32> ExpandoObjectTesting.Program::CS$<>9__CachedAnonymousMethodDelegate15
    L_01eb: brtrue.s L_0200
    L_01ed: ldnull 
    L_01ee: ldftn int32 ExpandoObjectTesting.Program::<Main>b__13(int32, int32)
    L_01f4: newobj instance void [mscorlib]System.Func`3<int32, int32, int32>::.ctor(object, native int)
    L_01f9: stsfld class [mscorlib]System.Func`3<int32, int32, int32> ExpandoObjectTesting.Program::CS$<>9__CachedAnonymousMethodDelegate15
    L_01fe: br.s L_0200
    L_0200: ldsfld class [mscorlib]System.Func`3<int32, int32, int32> ExpandoObjectTesting.Program::CS$<>9__CachedAnonymousMethodDelegate15
    L_0205: callvirt instance !3 [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite, object, class [mscorlib]System.Func`3<int32, int32, int32>, object>::Invoke(!0, !1, !2)
    L_020a: pop 
    L_020b: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site6
    L_0210: brtrue.s L_025b
    L_0212: ldc.i4.0 
    L_0213: ldstr "WriteLine"
    L_0218: ldtoken ExpandoObjectTesting.Program
    L_021d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_0222: ldnull 
    L_0223: ldc.i4.3 
    L_0224: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_0229: stloc.1 
    L_022a: ldloc.1 
    L_022b: ldc.i4.0 
    L_022c: ldc.i4.s 0x21
    L_022e: ldnull 
    L_022f: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_0234: stelem.ref 
    L_0235: ldloc.1 
    L_0236: ldc.i4.1 
    L_0237: ldc.i4.3 
    L_0238: ldnull 
    L_0239: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_023e: stelem.ref 
    L_023f: ldloc.1 
    L_0240: ldc.i4.2 
    L_0241: ldc.i4.0 
    L_0242: ldnull 
    L_0243: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_0248: stelem.ref 
    L_0249: ldloc.1 
    L_024a: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpCallFlags, string, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [mscorlib]System.Type>, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
    L_024f: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_0254: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site6
    L_0259: br.s L_025b
    L_025b: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site6
    L_0260: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>>::Target
    L_0265: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site6
    L_026a: ldtoken [mscorlib]System.Console
    L_026f: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_0274: ldstr "X: {0}"
    L_0279: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site7
    L_027e: brtrue.s L_02b2
    L_0280: ldstr "IntX"
    L_0285: ldtoken ExpandoObjectTesting.Program
    L_028a: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_028f: ldc.i4.1 
    L_0290: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_0295: stloc.1 
    L_0296: ldloc.1 
    L_0297: ldc.i4.0 
    L_0298: ldc.i4.0 
    L_0299: ldnull 
    L_029a: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_029f: stelem.ref 
    L_02a0: ldloc.1 
    L_02a1: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpGetMemberBinder::.ctor(string, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
    L_02a6: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_02ab: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site7
    L_02b0: br.s L_02b2
    L_02b2: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site7
    L_02b7: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>>::Target
    L_02bc: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site7
    L_02c1: ldloc.0 
    L_02c2: callvirt instance !2 [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>::Invoke(!0, !1)
    L_02c7: callvirt instance void [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>::Invoke(!0, !1, !2, !3)
    L_02cc: nop 
    L_02cd: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site8
    L_02d2: brtrue.s L_031d
    L_02d4: ldc.i4.0 
    L_02d5: ldstr "WriteLine"
    L_02da: ldtoken ExpandoObjectTesting.Program
    L_02df: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_02e4: ldnull 
    L_02e5: ldc.i4.3 
    L_02e6: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_02eb: stloc.1 
    L_02ec: ldloc.1 
    L_02ed: ldc.i4.0 
    L_02ee: ldc.i4.s 0x21
    L_02f0: ldnull 
    L_02f1: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_02f6: stelem.ref 
    L_02f7: ldloc.1 
    L_02f8: ldc.i4.1 
    L_02f9: ldc.i4.3 
    L_02fa: ldnull 
    L_02fb: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_0300: stelem.ref 
    L_0301: ldloc.1 
    L_0302: ldc.i4.2 
    L_0303: ldc.i4.0 
    L_0304: ldnull 
    L_0305: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_030a: stelem.ref 
    L_030b: ldloc.1 
    L_030c: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpCallFlags, string, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [mscorlib]System.Type>, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
    L_0311: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_0316: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site8
    L_031b: br.s L_031d
    L_031d: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site8
    L_0322: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>>::Target
    L_0327: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site8
    L_032c: ldtoken [mscorlib]System.Console
    L_0331: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_0336: ldstr "Y: {0}"
    L_033b: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site9
    L_0340: brtrue.s L_0374
    L_0342: ldstr "IntY"
    L_0347: ldtoken ExpandoObjectTesting.Program
    L_034c: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_0351: ldc.i4.1 
    L_0352: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_0357: stloc.1 
    L_0358: ldloc.1 
    L_0359: ldc.i4.0 
    L_035a: ldc.i4.0 
    L_035b: ldnull 
    L_035c: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_0361: stelem.ref 
    L_0362: ldloc.1 
    L_0363: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpGetMemberBinder::.ctor(string, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
    L_0368: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_036d: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site9
    L_0372: br.s L_0374
    L_0374: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site9
    L_0379: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>>::Target
    L_037e: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site9
    L_0383: ldloc.0 
    L_0384: callvirt instance !2 [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>::Invoke(!0, !1)
    L_0389: callvirt instance void [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>::Invoke(!0, !1, !2, !3)
    L_038e: nop 
    L_038f: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Sitea
    L_0394: brtrue.s L_03df
    L_0396: ldc.i4.0 
    L_0397: ldstr "WriteLine"
    L_039c: ldtoken ExpandoObjectTesting.Program
    L_03a1: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_03a6: ldnull 
    L_03a7: ldc.i4.3 
    L_03a8: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_03ad: stloc.1 
    L_03ae: ldloc.1 
    L_03af: ldc.i4.0 
    L_03b0: ldc.i4.s 0x21
    L_03b2: ldnull 
    L_03b3: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_03b8: stelem.ref 
    L_03b9: ldloc.1 
    L_03ba: ldc.i4.1 
    L_03bb: ldc.i4.3 
    L_03bc: ldnull 
    L_03bd: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_03c2: stelem.ref 
    L_03c3: ldloc.1 
    L_03c4: ldc.i4.2 
    L_03c5: ldc.i4.0 
L_03c6: ldnull 
    L_03c7: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_03cc: stelem.ref 
    L_03cd: ldloc.1 
    L_03ce: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpCallFlags, string, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [mscorlib]System.Type>, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
    L_03d3: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_03d8: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Sitea
    L_03dd: br.s L_03df
    L_03df: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Sitea
    L_03e4: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>>::Target
    L_03e9: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Sitea
    L_03ee: ldtoken [mscorlib]System.Console
    L_03f3: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_03f8: ldstr "Name: {0}"
    L_03fd: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Siteb
    L_0402: brtrue.s L_0436
    L_0404: ldstr "Name"
    L_0409: ldtoken ExpandoObjectTesting.Program
    L_040e: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_0413: ldc.i4.1 
    L_0414: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_0419: stloc.1 
    L_041a: ldloc.1 
    L_041b: ldc.i4.0 
    L_041c: ldc.i4.0 
    L_041d: ldnull 
    L_041e: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_0423: stelem.ref 
    L_0424: ldloc.1 
    L_0425: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpGetMemberBinder::.ctor(string, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
    L_042a: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_042f: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Siteb
    L_0434: br.s L_0436
    L_0436: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Siteb
    L_043b: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>>::Target
    L_0440: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Siteb
    L_0445: ldloc.0 
    L_0446: callvirt instance !2 [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>::Invoke(!0, !1)
    L_044b: callvirt instance void [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>::Invoke(!0, !1, !2, !3)
    L_0450: nop 
    L_0451: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Sitec
    L_0456: brtrue.s L_04a1
    L_0458: ldc.i4.0 
    L_0459: ldstr "WriteLine"
    L_045e: ldtoken ExpandoObjectTesting.Program
    L_0463: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_0468: ldnull 
    L_0469: ldc.i4.3 
    L_046a: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_046f: stloc.1 
    L_0470: ldloc.1 
    L_0471: ldc.i4.0 
    L_0472: ldc.i4.s 0x21
    L_0474: ldnull 
    L_0475: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_047a: stelem.ref 
    L_047b: ldloc.1 
    L_047c: ldc.i4.1 
    L_047d: ldc.i4.3 
    L_047e: ldnull 
    L_047f: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_0484: stelem.ref 
    L_0485: ldloc.1 
    L_0486: ldc.i4.2 
    L_0487: ldc.i4.0 
    L_0488: ldnull 
    L_0489: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_048e: stelem.ref 
    L_048f: ldloc.1 
    L_0490: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpCallFlags, string, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [mscorlib]System.Type>, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
    L_0495: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_049a: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Sitec
    L_049f: br.s L_04a1
    L_04a1: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Sitec
    L_04a6: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>>::Target
    L_04ab: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Sitec
    L_04b0: ldtoken [mscorlib]System.Console
    L_04b5: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_04ba: ldstr "Multiply(X, Y): {0}"
    L_04bf: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`5<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Sited
    L_04c4: brtrue.s L_050e
    L_04c6: ldc.i4.0 
    L_04c7: ldstr "Multiply"
    L_04cc: ldtoken ExpandoObjectTesting.Program
    L_04d1: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_04d6: ldnull 
    L_04d7: ldc.i4.3 
    L_04d8: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_04dd: stloc.1 
    L_04de: ldloc.1 
    L_04df: ldc.i4.0 
    L_04e0: ldc.i4.0 
    L_04e1: ldnull 
    L_04e2: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_04e7: stelem.ref 
    L_04e8: ldloc.1 
    L_04e9: ldc.i4.1 
    L_04ea: ldc.i4.0 
    L_04eb: ldnull 
    L_04ec: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_04f1: stelem.ref 
    L_04f2: ldloc.1 
    L_04f3: ldc.i4.2 
    L_04f4: ldc.i4.0 
    L_04f5: ldnull 
    L_04f6: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_04fb: stelem.ref 
    L_04fc: ldloc.1 
    L_04fd: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpCallFlags, string, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [mscorlib]System.Type>, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
    L_0502: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`5<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object, object, object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_0507: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`5<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Sited
    L_050c: br.s L_050e
    L_050e: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`5<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Sited
    L_0513: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`5<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object, object, object>>::Target
    L_0518: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`5<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Sited
    L_051d: ldloc.0 
    L_051e: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Sitee
    L_0523: brtrue.s L_0557
    L_0525: ldstr "IntX"
    L_052a: ldtoken ExpandoObjectTesting.Program
    L_052f: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_0534: ldc.i4.1 
    L_0535: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_053a: stloc.1 
    L_053b: ldloc.1 
    L_053c: ldc.i4.0 
    L_053d: ldc.i4.0 
    L_053e: ldnull 
    L_053f: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_0544: stelem.ref 
    L_0545: ldloc.1 
    L_0546: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpGetMemberBinder::.ctor(string, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
    L_054b: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_0550: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Sitee
    L_0555: br.s L_0557
    L_0557: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Sitee
    L_055c: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>>::Target
    L_0561: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Sitee
    L_0566: ldloc.0 
    L_0567: callvirt instance !2 [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>::Invoke(!0, !1)
    L_056c: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Sitef
    L_0571: brtrue.s L_05a5
    L_0573: ldstr "IntY"
    L_0578: ldtoken ExpandoObjectTesting.Program
    L_057d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_0582: ldc.i4.1 
    L_0583: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_0588: stloc.1 
    L_0589: ldloc.1 
    L_058a: ldc.i4.0 
    L_058b: ldc.i4.0 
    L_058c: ldnull 
    L_058d: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_0592: stelem.ref 
    L_0593: ldloc.1 
    L_0594: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpGetMemberBinder::.ctor(string, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
    L_0599: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_059e: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Sitef
    L_05a3: br.s L_05a5
    L_05a5: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Sitef
    L_05aa: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>>::Target
    L_05af: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Sitef
    L_05b4: ldloc.0 
    L_05b5: callvirt instance !2 [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>::Invoke(!0, !1)
    L_05ba: callvirt instance !4 [mscorlib]System.Func`5<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object, object, object>::Invoke(!0, !1, !2, !3)
    L_05bf: callvirt instance void [mscorlib]System.Action`4<class [System.Core]System.Runtime.CompilerServices.CallSite, class [mscorlib]System.Type, string, object>::Invoke(!0, !1, !2, !3)
    L_05c4: nop 
    L_05c5: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site10
    L_05ca: brtrue.s L_060a
    L_05cc: ldc.i4.0 
    L_05cd: ldstr "SayHello"
    L_05d2: ldtoken ExpandoObjectTesting.Program
    L_05d7: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_05dc: ldnull 
    L_05dd: ldc.i4.2 
    L_05de: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_05e3: stloc.1 
    L_05e4: ldloc.1 
    L_05e5: ldc.i4.0 
    L_05e6: ldc.i4.0 
    L_05e7: ldnull 
    L_05e8: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_05ed: stelem.ref 
    L_05ee: ldloc.1 
    L_05ef: ldc.i4.1 
    L_05f0: ldc.i4.0 
    L_05f1: ldnull 
    L_05f2: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_05f7: stelem.ref 
    L_05f8: ldloc.1 
    L_05f9: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpCallFlags, string, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [mscorlib]System.Type>, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
    L_05fe: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_0603: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site10
    L_0608: br.s L_060a
    L_060a: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site10
    L_060f: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>>::Target
    L_0614: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site10
    L_0619: ldloc.0 
    L_061a: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site11
    L_061f: brtrue.s L_0653
    L_0621: ldstr "Name"
    L_0626: ldtoken ExpandoObjectTesting.Program
    L_062b: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_0630: ldc.i4.1 
    L_0631: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_0636: stloc.1 
    L_0637: ldloc.1 
    L_0638: ldc.i4.0 
    L_0639: ldc.i4.0 
    L_063a: ldnull 
    L_063b: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::.ctor(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_0640: stelem.ref 
    L_0641: ldloc.1 
    L_0642: newobj instance void [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpGetMemberBinder::.ctor(string, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
    L_0647: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_064c: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site11
    L_0651: br.s L_0653
    L_0653: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site11
    L_0658: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>>::Target
    L_065d: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>> ExpandoObjectTesting.Program/<Main>o__SiteContainer0::<>p__Site11
    L_0662: ldloc.0 
    L_0663: callvirt instance !2 [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>::Invoke(!0, !1)
    L_0668: callvirt instance void [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, object>::Invoke(!0, !1, !2)
    L_066d: nop 
    L_066e: call string [mscorlib]System.Console::ReadLine()
    L_0673: pop 
    L_0674: ret 
}
 

För att göra en lång historia kort... Det som sker är att det först skapas upp en instans av ExpandoObject, vilket ger ett object. Sedan används ett antal CallSites för att skapa upp en dynamisk call site som har hand om alla dynamiska handlingar som sker mot objektet.

När objektet binds så returneras ett expression tree med data för objektet, vilket sedan används för att arbeta med de metoder och den data som vi tidigare har skapat.

Då objekten skapas upp under runtime så kan vi även använda dem runt om i applikationen, vilket gör att vi kan göra t.ex. så här:

static dynamic GetExpendo()
{
    dynamic magic = new ExpandoObject();
 
    magic.IntX = 10;
    magic.IntY = 20;
    magic.Name = "Nisse";
    magic.SayHello = new Action<string>(x => Console.WriteLine("Hello, " + x + "!"));
    magic.Multiply = new Func<int, int, int>((x, y) => x * y);
 
    return magic;
}

Vi kan sedan skapa upp objektet genom:

dynamic magic = GetExpendo();

Det här fungerar lika bra som innan. Med andra ord så behandlas dynamiska ExpandoObject-instanser på samma sätt som vanliga statiska instanser.

I C# 4.0 så kommer ett nytt keyword kallat ”dynamic”. Precis som ”var” i C# 3.5 så säger det inget om vilken typ det är när man skriver. Skillnaden mot var är att var blir hårt typad vid kompilering, medan dynamic blir det vid runtime.

Så, varför skulle vi vilja typa variablerna vid runtime? När man arbetar med COM som i t.ex. Office-biblioteken så är inte allt hårt typat, när man anropar DOM:en via Silverlight så är det inte heller starkt typat mot det enskilta objektet och om vi vill köra kod i ett språk baserat på DLR så är det förstås inte heller starkt typat.

Det vi kan göra med dynamic är att vi kan anropa en metod i något av dessa bibliotek trots att .NET inte känner till att metoden finns under kompileringen. När vi däremot kör koden så ser .NET att objektet finns, och kör därefter den metoden vi just bad om.

Istället för att ta ett objekt och peka på en metod som vi vill anropa så tar vi ett objekt och säger att vi vill anropa en metod med ett visst namn.

Fördelen med det här är att vi enkelt kan anropa metoder som nödvändigtvis inte behöver när vi kompilerar, men som kommer att finnas när vi kör applikationen. Om nu inte metoden finns så får vi ett felmeddelande när vi anropar metoden.

Men varför vill vi blanda t.ex. C# och IronRuby i våra applikationer? Tänk dig att vi har en applikation som vi vill att användarna skall kunna bygga ut enkelt. Om vi skriver applikationen i C# och vill utöka funktionaliteten med t.ex. C# eller Visual Basic så kan vi använda MEF eller liknande för att få den funktionaliteten. Det här kräver dock att användaren skriver sin kod, kompilerar den och sedan lägger den i en mapp som vi sedan läser in. Fördelen med ett dynamiskt språk som IronRuby är att den inte behöver kompileras, utan kan köras direkt. Vi gör det därmed möjligt för personer att enkelt skriva ihop en fil som gör det de vill och sedan låter dem injicera koden i vår applikation.

I exemplet jag kommer att gå igenom så använder jag Visual Studio 2010 Beta 1 med .NET 4.0 Beta 1 och den versionen av IronRuby som finns tillgänglig för just dessa. IronRuby för .NET 4.0 Beta 1 finns att ladda ned här:

http://ironruby.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=27606

Vi börjar med att skapa ett console-projekt och lägger till referenser till Microsoft.Scripting, IronRuby och IronRuby.Libraries. Det finns även assemblies för IronPython för de som föredrar det.

Applikationen vi ska skriva nu kommer att hämta alla rb-filer (IronRuby) och köra en metod vid namn ”sayhello” i klassen ”RubyTest”.

Jag kommer att ha två olika rb-filer i exemplet, den ena skriver ut en rad direkt i programmet, och den andra kommer att visa en MessageBox med det inmatade värdet.

Console.rb:

class RubyTest
  def sayhello
    input = System::Console.ReadLine
    System::Console::WriteLine "Ruby says: " + input
  end
end

msgbox.rb

require 'System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
 
class RubyTest
  def sayhello
    input = System::Console.ReadLine
    System::Windows::Forms::MessageBox.Show input, "Ruby says"
  end
end

I båda fallen så läser vi in en sträng i programmet som vi sedan använder oss utav. Vi kommer alltså åt programmet utan att filerna på något sätt har med det att göra, utöver det faktum att de körs från det.

Det vi behöver göra nu är att läsa in filerna från console-programmet och köra sayhello-metoderna.

Grundstommen för vårt program ser ut så här:

using System;
using System.IO;
using IronRuby;
using Microsoft.Scripting.Hosting;
 
namespace IronRubyConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            DirectoryInfo di = new DirectoryInfo(Environment.CurrentDirectory + "\\scripts");
 
            CallRuby(di.GetFiles("*.rb"));
 
            Console.ReadKey();
        }
 
        private static void CallRuby(FileInfo[] files)
        {
            foreach (FileInfo file in files)
            {
                Console.WriteLine("{0}------------{0}{1}{0}------------", Environment.NewLine, file.Name);
                ExecuteRuby(file.FullName);
            }
        }
 
        private static void ExecuteRuby(string path)
        {
 
        }
    }
}

Vi loopar igenom alla rb-filer i mappen “scripts” som ligger i samma mapp som exe-filen. Sedan anropar vi metoden ExecuteRuby() där vi kommer att köra filerna.

Koden som vi använder i ExecuteRuby är:

ScriptEngine engine = Ruby.CreateEngine();
engine.ExecuteFile(path);
object rubyclass = engine.Runtime.Globals.GetVariable("RubyTest");
dynamic rubytest = engine.Operations.CreateInstance(rubyclass);
 
rubytest.sayhello();

För att köra våra IronRuby-filer så behöver vi skapa ett ScriptEnginge-objekt som finns under Microsoft.Scripting.Hosting. Den ScriptEnginge vi använder är den som finns för IronRuby. Det finns även en för IronPython.

När vi har en ScriptEngine så kan vi exekvera filen som vi fick in via parametern.

Sedan anropar vi klassen RubyTest och skapar en instans av den.

Då variabeln ”rubytest” är satt som dynamic så kan vi anropa vilken metod som helst och kompilera, även om metoden inte är skapad än. Det kan vi se på den nedersta raden, ”rubytest.sayhello();”.

Om sayhello tar emot en parameter i IronRuby-filen så kan vi skicka med den som vanligt i anropet.

När vi nu kör applikationen och fyller den med text så får vi upp det här:

1 - Execute

Vi kan alltså på ett väldigt enkelt sätt göra det möjligt för användarna av våra program att skriva script i IronRuby och andra dynamiska språk.

Jag har lagt upp projektet här (kräver .NET 4.0 Beta 1 för att kunna köras):

http://cid-4aa13e17331c7398.skydrive.live.com/self.aspx/Public/VS%202010%20%5E0%20.NET%204.0/IronRubyConsole.rar

More Posts Next page »