Bookmark and Share

Missing a Section Declaration After Upgrade

by KodefuGuru 27. August 2010 00:02

In the process of installing Orchard tonight, I encountered the following error.

The configuration section 'system.web.extensions' cannot be read because it is missing a section declaration.

The web.config clearly had an empty system.web.extension section.

<system.web.extensions/>

But there was no corresponding section declaration, just like the error said. However, Orchard runs fine on my local machine, and I’ve deployed it to my server before. What could be going on?

It turns out that it’s quite a simple issue, and probably a common problem. If you upgrade a site to .NET 4, and don’t upgrade the application pool to use .NET 4, you will get this. The machine.config file for .NET 4 declares this section, and earlier version did not have it (unless you manually added it).

In IIS 7, with the site select, choose Basic Settings in the right pane. This will bring up a dialog that contains the name of your application pool. Then select the application pools tree node and the application pool from the list that shows up. Choose Basic Settings from the right pane here, and you can change the framework version.

Bookmark and Share

A Practical Guide to ASP.NET 3.5

by KodefuGuru 12. December 2009 23:14

ASP.NET 3.5 Website Programming: Problem - Design - Solution The author of ASP.NET 3.5 Website Programming: Problem - Design - Solution came to our town to talk about the lessons learned from developing with the Entity Framework with the Beer House project. It was great, and I had to purchase the book when it became available! He walks you through developing a real-life application in ASP.NET 3.5 using the Entity Framework; no impractical examples here.

Many developers dive into writing an application without giving consideration to the overall architectural concerns that are necessary for a well-designed web application. Chris Love walks you through these concerns from the multiple application tiers to logging, instrumentation, and finally deployment.

I am currently a fan of ASP.NET MVC, but if you're still programming Web Forms, and many are, this is the book for you.

Bookmark and Share

Automating KiGG Publishing

by KodefuGuru 14. July 2009 19:17

This is part 1 of a series on KiGG Automation.

Part 1: Automating KiGG Publishing
Part 2: KiGG’s Story Summary 
Part 3: Automating KiGG Submission

When I set up my first KiGG site, I was surprised to discover that I had to manually publish articles. I assumed it would be an automated process that would run once a day. Since there are times I may not be able to log into my website, I set about figuring out how to automate the process.

I should note that during this process, I didn’t use best practices. I had one requirement: make a program that I can schedule to publish stories on KiGG. I wasn’t really sure what I would need to go about doing that. So, I did what I assume most developers do: create a console application prototype. I don’t claim this code is perfect, but if you want classes to automate publishing in KiGG (or control MVC applications), this will do the trick.

KiGG is an ASP.NET MVC application. This made it easy to figure out where to begin. I wanted to Publish, so I needed to find the admin link and see what it called. I guessed it would be something like, /Publish, and I was correct.

scriptManager.RegisterOnReady("Administration.set_publishUrl('{0}');"
    .FormatWith(Url.RouteUrl("Publish")));

set_publishUrl is simply a setter in the JavaScript to prevent a url from being hardcoded in script. Looking over the JavaScript I could tell there wasn’t much more needed than calling the proper url.

$.ajax(
    {
        url: Administration._publishUrl,
        type: 'POST',
        dataType: 'json',
        data : '__MVCASYNCPOST=true', // a fake param to fool iis for content-lenth,
        beforeSend: function()
        {
            $U.showProgress('Publishing stories...');
        },
        success: function(result)
        {
            $U.hideProgress();

            if (result.isSuccessful)
            {
                $U.messageBox('Success', 'Story publishing process completed.', false);
            }
            else
            {
                $U.messageBox('Error', result.errorMessage, true);
            }
        }
    }
);

The script is doing a POST on the /Publish url with fake data (to fool IIS?).

Next, it was time to check the routing for /Publish. Routing in KiGG is defined in Kigg.Web\BootstrapperTasks\RegisterRoutes.cs. It was done this way to be consistent with the Open Closed Principle.

_routes.MapRoute("Publish", "Publish", 
    new { controller = "Story", action = "Publish" });

Now we know the entry to this is in the story controller and that the method is Publish. The story controller being used is defined within the web.config file using Unity.

<typeAlias alias="StoryController" type="Kigg.Web.StoryController, Kigg.Web"/>

I set up a break point and wrote a quick routine to post to the publish url.

var request = WebRequest.Create(http://localhost:1736/Publish);
request.ContentType = "application/x-www-form-urlencoded"; request.Method = "POST"; var form = Encoding.ASCII.GetBytes("__MVCASYNCPOST=true"); using (Stream requestStream = request.GetRequestStream()) { requestStream.Write(form, 0, form.Length); requestStream.Close(); } var response = request.GetResponse(); using (StreamReader reader = new StreamReader(response.GetResponseStream())) { var responseText = reader.ReadToEnd(); Debug.WriteLine(responseText); reader.Close(); }

Everything executed fine, but the return message indicated something was wrong: “{"isSuccessful":false,"errorMessage":"You are currently not authenticated."}.” It’s pretty obvious that authentication would be necessary, otherwise I could publish DotNetShoutOut whenever I wanted. Unfortunately, the obvious way to authenticate does not work.

request.Credentials = new NetworkCredential("admin", "password");

Since it is a NetworkCredential, I assume this code would work with Windows authentication turned on. However, we’re using forms authentication. I looked at the routes and found one for Login and Logout. At this point it was clear that I would be calling post multiple times, so I moved the code to a method that would accept a url and formdata as a string.

Post("http://localhost:1736/Login", "userName=admin&password=password");
Post("http://localhost:1736/Publish", "__MVCASYNCPOST=true");
Post("http://localhost:1736/Logout", "__MVCASYNCPOST=true");

This returned the following results:

{"isSuccessful":true,"errorMessage":null}
{"isSuccessful":false,"errorMessage":"You are currently not authenticated."}
{"isSuccessful":false,"errorMessage":"You are currently not logged in."}

I put a breakpoint in the Login method of the MembershipController, and from there was able to see what was happening. Although it was a few levels deep, it was clear that FormsAuthentication.SetAuthCookie was the important piece of code; I needed a way to retain cookies between requests.

Cookies are only available by using HttpWebRequest and HttpWebReponse rather than their base classes. So, I cast my variables to the proper class. One odd thing I found was the cookies have to be retrieved from the request rather than the response after you have requested the response. I wrapped this functionality up in a WebSession class.

public class WebSession
{
    protected CookieCollection Cookies { get; set; }

    public WebSession()
    {
        Cookies = new CookieCollection();
    }

    public string Post(string url, HttpDictionary formData)
    {
        return Post(url, formData.ToString());
    }

    public string Post(string url, string formData)
    {            
        var request = WebRequest.Create(url) as HttpWebRequest;
        if (request == null)
        {
            throw new HttpException();
        }
        request.ContentType = "application/x-www-form-urlencoded";
        request.Method = "POST";
        request.CookieContainer = new CookieContainer();
        request.CookieContainer.Add(request.RequestUri, Cookies);

        var form = Encoding.ASCII.GetBytes(formData);
        WriteToRequest(request, form);

        var response = request.GetResponse() as HttpWebResponse;
        if (response == null)
        {
            throw new HttpException();
        }

        var responseText = ReadResponse(response);
        Cookies = request.CookieContainer.GetCookies(request.RequestUri);

        Debug.WriteLine(responseText);
        
        return responseText;
    }

    private static void WriteToRequest(WebRequest request, byte[] form)
    {
        using (Stream requestStream = request.GetRequestStream())
        {
            requestStream.Write(form, 0, form.Length);
            requestStream.Close();
        }
    }

    private string ReadResponse(WebResponse response)
    {
        using (StreamReader reader = 
            new StreamReader(response.GetResponseStream()))
        {
            var responseText = reader.ReadToEnd();
            reader.Close();
            return responseText;
        }
    }
}

If you look closely you’ll notice an HttpDictionary class. This is because I wanted to treat the form data as a dictionary rather than a string. I suppose this could be written as an extension method on Dictionary<string, string> instead.

public class HttpDictionary : Dictionary<string, string>
{
    public override string ToString()
    {
        return this.Select(q => EncodePair(q))
            .Aggregate((a, b) => a + "&" + b);
    }

    private string EncodePair(KeyValuePair<string, string> pair)
    {
        return HttpUtility.HtmlEncode(pair.Key) +
            "=" + HttpUtility.HtmlEncode(pair.Value);
    }
}

I also felt it necessary to wrap up the result received from KiGG in a class that can be used. Otherwise, it’s difficult to know whether or not the call was successful. To convert from Json, I used Json.NET.

public class KiggResult
{        
    [JsonProperty(PropertyName="isSuccessful")]
    public bool IsSuccessful{ get; set; }

    [JsonProperty(PropertyName = "errorMessage")]
    public string ErrorMessage { get; set; }

    public static KiggResult Create(string json)
    {
        return JsonConvert.DeserializeObject<KiggResult>(json);
    }
}

Finally, I made a KiggBot class to provide us an interface that makes sense for accessing a KiGG site. This can be changed to throw an exception if the result indicates the call was not successful.

public class KiggBot 
{
    private static readonly HttpDictionary mvcAsyncPost = new HttpDictionary
    {
        {"__MVCASYNCPOST", "true"}
    };

    private WebSession session;
    private string url;

    public KiggBot(string url)
    {
        if (!url.EndsWith("/"))
            url += "/";

        this.url = url;
        session = new WebSession();
    }

    public bool Login(string userName, string password)
    {
        HttpDictionary dictionary = new HttpDictionary { 
            {"userName", userName}, {"password", password}};

        var result = KiggResult.Create(
            session.Post(url + "Login", dictionary));
        
        return result.IsSuccessful;
    }

    public bool Logout()
    {
        var result = KiggResult.Create(
            session.Post(url + "Logout", mvcAsyncPost));

        return result.IsSuccessful;
    }

    public bool Publish()
    {
        var result = KiggResult.Create(
            session.Post(url + "Publish", mvcAsyncPost));

        return result.IsSuccessful;
    }
}

With these classes, it’s fairly easy to create an automated publishing program. At the very least, write a console app and use scheduler to fire it daily.

KiggBot bot = new KiggBot("http://localhost:1736");
bot.Login("admin", "password");
bot.Publish();
bot.Logout();
Hope that helps. If anyone makes a cool GUI for this and releases it, might I recommend PiGG?
Bookmark and Share

MDC Atlanta

by KodefuGuru 15. December 2008 10:01

I'm leaving for Atlanta tonight to attend MDC tomorrow. I will also attend the Influencer Reception after the conference. My goal is to soak up as much information about Azure Services and Live Mesh that I can and attend C# 4.0 presentations to get pointers for my own presentation that I will be giving at user groups.

Here's my planned schedule:

10:15-11:30 The Future of Managed Languages: C# and Visual Basic
12:30-1:45 Developing and Deploying Your First Azure Service
2:00-3:15 A Lap Around the Live Framework and Mesh Services 
3:30-4:45 ASP.NET 4.0 Roadmap 
6:00-??? Influencer Reception
 

KodefuGuru.GetInfo()

Chris Eargle
LinkedIn Twitter Technorati Facebook

Chris Eargle
C# MVP, INETA Community Champion


MVP - Visual C#

 

INETA Community Champions
Friend of RedGate
Telerik .NET Ninja
Community blogs & blog posts

I am a #52er

I have joined Anti-IF Campaign


World Map

Tag cloud

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010