|
|
|
Related Articles
|
|
|
|
| |
It's not very often that you see something new in News.
News is not exactly new technology, but when personal computers came along, and then widespread networking, it created a whole new playing field for news, that has shaken things up for most of my life. Change comes in fits at starts. First there was the web, then RSS, and now I think we're on the cusp of another bit of change.
If you want to see what I think it looks like, check out the home page of nytimesriver.com. But that's not the end of the story. A flat completely chronologic view of news probably isn't enough. And earlier this month at a meeting in NY, two engineers at the NY Times set me off in a new direction, with a very simple bit of advice. They told me to look in the HTML source code of their stories. When I did I saw they had applied a taxonomy to their news flow, and this opened the door to what I would like to show you today -- an outline view of the news.
http://nytimesriver.com/outline/
I believe it's fairly self-explanatory.
The topics are arranged in order of frequency in today's news.
In a previous rendering, the stories were shown in a histogram, but this view I think is much better. You can still see how many pieces relate to the indicated topic, but by clicking on the plus next to each topic, you can actually see the headlines and descriptions, and if you want more you can click through to the full stories. (Initially, the outline was sorted by frequency, with the most frequently occurring keyword appearing first. I changed it, based on feedback, to be alphabetic.)
Now, there's still more to do, I showed this to a number of people during the weekend and got some excellent clues on ideas to pursue next, and I will do that. Further, in the process of exploring this, I've been shown the work of other developers who discovered the keywords on their own, and one in particular is very interesting. I'm hoping that these projects will come public so I can show them to you and tell you what I think they mean.
This is what I live for, professionally -- the sense of being somewhere with great unexplored potential, a virgin landscape of the intellect. I'm never happier than when I get to play in such a place.
Scott Rosenberg: Remixing news.
Om Malik: A new way to view news.
Please comment on the screen shot page. |
| |
|
| |
| |
When you are website writing, keyword density should be at the top of the list for things you want to check for your seo (search engine optimization, which means you want to include what the searc... |
| |
|
| |
| |
When you are website writing, keyword density should be at the top of the list for things you want to check for your seo (search engine optimization, which means you want to include what the search engines like on a site to put you on the top of a search). |
| |
|
| |
| |
Around the turning corner of year 2007, there was a site about Chinese culture on top 3, sometimes top 6, in the target keyword phrase new year. (I made this keyword up as an example. If you check on Google, you wouldnt find this site because I dont want my client exposed. Indeed, it was a similar keyword.) Around February 2007, all the sudden the site became top 1 in this keyword although there was no change in the content or the link profile. Thats because February is ... |
| |
|
| |
| |
Not content with your site's page rank? Of course you want to be on the first twenty search results when somebody typed in the keyword you are targeting. However, you are apparently getting nowhere. Perhaps its time to do something about it.
--- Keyword Density Misconceptions
One of the first things you should check is your pages keyword density. Check your articles content. They say, to increase the traffic in your site, you need to maintain a keyword density of 2% ... |
| |
|
| |
| |
A free way to get basically the same information is to first check out Digital Point Solutions keyword tool. That provides you with the daily Google and Yahoo demand for each keyword. Enter your possible keywords into the search box and note those with most demand. Then go to Google, and enter the same keywords into your browser and find the Google supply. This is given toward the top right of the results, above the Adsense adverts. You can then marry the two and manually calculate what Wordtracker does for you. Once you have the keywords you have to know how to use them. That is another subject, but basically you should... |
| |
|
| |
| |
Last week I started the first in a series of blog posts I'll be making that cover some of the new VB and C# language features that are coming as part of the Visual Studio and .NET Framework "Orcas" release later this year. My last blog post covered the new Automatic Properties, Object Initializer and Collection Initializer features. If you haven't read my previous post yet, please read it here. Today's blog post covers a much more significant new feature that is available with both VB and C#: Extension Methods. What are Extension Methods? Extension methods allow developers to add new methods to the public contract of an existing CLR type, without having to sub-class it or recompile the original type. Extension Methods help blend the flexibility of "duck typing" support popular within dynamic languages today with the performance and compile-time validation of strongly-typed languages. Extension Methods enable a variety of useful scenarios, and help make possible the really powerful LINQ query framework that is being introduced with .NET as part of the "Orcas" release. Simple Extension Method Example: Ever wanted to check to see whether a string variable is a valid email address? Today you'd probably implement this by calling a separate class (probably with a static method) to check to see whether the string is valid. For example, something like: string email = Request.QueryString["email"];if ( EmailValidator.IsValid(email) ) { } Using the new "extension method" language feature in C# and VB, I can instead add a useful "IsValidEmailAddress()" method onto the string class itself, which returns whether the string instance is a valid string or not. I can then re-write my code to be cleaner and more descriptive like so: string email = Request.QueryString["email"];if ( email.IsValidEmailAddress() ) { } How did we add this new IsValidEmailAddress() method to the existing string type? We did it by defining a static class with a static method containing our "IsValidEmailAddress" extension method like below: public static class ScottGuExtensions{ public static bool IsValidEmailAddress(this string s) { Regex regex = new Regex(@"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"); return regex.IsMatch(s); }} Note how the static method above has a "this" keyword before the first parameter argument of type string. This tells the compiler that this particular Extension Method should be added to objects of type "string". Within the IsValidEmailAddress() method implementation I can then access all of the public properties/methods/events of the actual string instance that the method is being called on, and return true/false depending on whether it is a valid email or not. To add this specific Extension Method implementation to string instances within my code, I simply use a standard "using" statement to import the namespace containing the extension method implementation: using ScottGuExtensions; The compiler will then correctly resolve the IsValidEmailAddress() method on any string. C# and VB in the public "Orcas" March CTP now provide full intellisense support for extension methods within the Visual Studio code-editor. So when I hit the "." keyword on a string variable, my extension methods will now show up in the intellisense drop-downlist: The VB and C# compilers also naturally give you compile-time checking of all Extension Method usage - meaning you'll get a compile-time error if you mis-type or mis-use one. [Credit: Thanks to David Hayden for first coming up with the IsValidEmailAddress scenario I used above in a prior blog post of his from last year.] Extension Methods Scenarios Continued... Leveraging the new extension method feature to add methods to individual types opens up a number of useful extensibility scenarios for developers. What makes Extension Methods really powerful, though, is their ability to be applied not just to individual types - but also to any parent base class or interface within the .NET Framework. This enables developers to build a variety of rich, composable, framework extensions that can be used across the .NET Framework. For example, consider a scenario where I want an easy, descriptive, way to check whether an object is already included within a collection or array of objects. I could define a simple .In(collection) extension method that I want to add to all objects within .NET to enable this. I could implement this "In()" extension method within C# like so: Note above how I've declared the first parameter to the extension method to be "this object o". This indicates that this extension method should applied to all types that derive from the base System.Object base type - which means I can now use it on every object in .NET. The "In" method implementation above allows me to check to see whether a specific object is included within an IEnumerable sequence passed as an argument to the method. Because all .NET collections and arrays implement the IEnumerable interface, I now have a useful and descriptive method for checking whether any .NET object belongs to any .NET collection or array. I could use then use this "In()" extension method to see whether a particular string is within an array of strings: I could use it to check to see whether a particular ASP.NET control is within a container control collection: I could even use it with scalar datatypes like integers: Note above how you can even use extension methods on base datatype values (like the integer value 42). Because the CLR supports automatic boxing/unboxing of value-classes, extensions methods can be applied on numeric and other scalar datatypes directly. As you can probably begin to see from the samples above, extension methods enable some really rich and descriptive extensibility scenarios. When applied against common base classes and interfaces across .NET, they enable some really nice domain specific framework and composition scenarios. Built-in System.Linq Extension Methods One of the built-in extension method libraries that we are shipping within .NET in the "Orcas" timeframe are a set of very powerful query extension method implementations that enable developers to easily query data. These extension method implementations live under the new "System.Linq" namespace, and define standard query operator extension methods that can be used by any .NET developer to easily query XML, Relational Databases, .NET Objects, and/or any other type of data structure. A few of the advantages of using the extension method extensibility model for this query support include: 1) It enables a common query programming model and syntax that can be used across all types of data (databases, XML files, in-memory objects, web-services, etc). 2) It is composable and allows developers to easily add new methods/operators into the query syntax. For example: we could use our custom "In()" method together with the standard "Where()" method defined by LINQ as part of a single query. Our custom In() method will look just as natural as the "standard" methods supplied under the System.Linq namespace. 3) It is extensible and allows any type of data provider to be used with it. For example: an existing ORM engine like NHibernate or LLBLGen could implement the LINQ standard query operators to enable LINQ queries against their existing ORM implementation and mapping engines. This will enable developers to learn a common way to query data, and then apply the same skills against a wide variety of rich data store implementations. I'll be walking through LINQ much more over the next few weeks, but wanted to leave you with a few samples that show how to use a few of the built-in LINQ query extension methods with different types of data: Scenario 1: Using LINQ Extension Methods Against In-Memory .NET Objects Assume we have defined a class to represent a "Person" like so: I could then use the new object Initializer and collection Initializer features to create and populate a collection of "people" like so: I could then use the standard "Where()" extension method provided by System.Linq to retrieve a sequence of those "Person" objects within this collection whose FirstName starts with the letter "S" like so: The new p => syntax above is an example of a "Lambda expression", which is a more concise evolution of C# 2.0's anonymous method support, and enables us to easily express a query filter with an argument (in this case we are indicating that we only want to return a sequence of those Person objects where the firstname property starts with the letter "S"). The above query will then return 2 objects as part of the sequence (for Scott and Susanne). I could also write code that takes advantage of the new "Average" and "Max" extension methods provided by System.Linq to determine the average age of the people in my collection, as well as the age of the oldest person like so: Scenario 2: Using LINQ Extension Methods Against an XML File It is probably rare that you manually create a collection of hard-coded data in-memory. More likely you'll retrieve the data either from an XML file, a database, or a web-service. Let's assume we have an XML file on disk that contains the data below: I could obviously use the existing System.Xml APIs today to either load this XML file into a DOM and access it, or use a low-level XmlReader API to manually parse it myself. Alternatively, with "Orcas" I can now use the System.Xml.Linq implementation that supports the standard LINQ extension methods (aka "XLINQ") to more elegantly parse and process the XML. The below code-sample shows how to use LINQ to retrieve all of the <person> XML Elements that have a <person> sub-node whose inner value starts with the letter "S": Note that it uses the exact same Where() extension method as with the in-memory object sample. Right now it is returning a sequence of "XElement" elements, which is an un-typed XML node element. I could alternatively re-write the query to "shape" the data that is returned instead by using LINQ's Select() extension method and provide a Lambda expression that uses the new object initializer syntax to populate the same "Person" class that we used with our first in-memory collection example: The above code does all the work necessary to open, parse and filter the XML in the "test.xml" file, and return back a strongly-typed sequence of Person objects. No mapping or persistence file is necessary to map the values - instead I am expressing the shaping from XML->objects directly within the LINQ query above. I could also use the same Average() and Max() LINQ extension methods as before to calculate the average age of <person> elements within the XML file, as well as the maximum age like so: I do not have to manually parse the XML file. Not only will XLINQ handle that for me, but it will parse the file using a low-level XMLReader and not have to create a DOM in order to evaluate the LINQ expression. This means that it is lightening fast and doesn't allocate much memory. Scenario 3: Using LINQ Extension Methods Against a Database Let's assume we have a SQL database that contains a table called "People" that has the following database schema: I could use the new LINQ to SQL WYSIWYG ORM designer within Visual Studio to quickly create a "Person" class that maps to the database: I can then use the same LINQ Where() extension method I used previously with objects and XML to retrieve a sequence of strongly-typed "Person" objects from the database whose first name starts with the letter "S": Note how the query syntax is the same as with objects and XML. I could then use the same LINQ Average() and Max() extension methods as before to retrieve the average and maximum age values from the database like so: You don't need to write any SQL code yourself to have the above code snippets work. The LINQ to SQL object relational mapper provided with "Orcas" will handle retrieving, tracking and updating objects that map to your database schema and/or SPROCs. You can simply use any LINQ extension method to filter and shape the results, and LINQ to SQL will execute the SQL code necessary to retrieve the data (note: the Average and Max extension methods above obviously don't return all the rows from the table - they instead use TSQL aggregate functions to compute the values in the database and just return a scalar result). Please watch this video I did in January to see how LINQ to SQL dramatically improves data productivity in "Orcas". In the video you can also see the new LINQ to SQL WYSIWYG ORM designer in action, as well as see full intellisense provided in the code-editor when writing LINQ code against the data model. Summary Hopefully the above post gives you a basic understanding of how extension methods work, and some of the cool extensibility approaches you will be able to take with them. As with any extensibility mechanism, I'd really caution about not going overboard creating new extension methods to begin with. Just because you have a shiny new hammer doesn't mean that everything in the world has suddenly become a nail! To get started trying out extension methods, I'd recommend first exploring the standard query operators provided within the System.Linq namespace in "Orcas". These enable rich query support against any array, collection, XML stream, or relational database, and can dramatically improve your productivity when working with data. I think you'll find they'll significantly reduce the amount of code you write within your applications, and allow you to write really clean and descriptive syntax. They'll also enable you to get automatic intellisense and compile-time checking of query logic within your code. In the next few weeks I'll continue this series on new language features in "Orcas" and explore Anonymous Types and Type Inference, as well as talk more about Lambdas and other cool features. I'll also obviously be talking a lot more about LINQ. Hope this helps, Scott |
| |
|
| |
| |
People often ask me for guidance on how they can dynamically "re-write" URLs and/or have the ability to publish cleaner URL end-points within their ASP.NET web applications. This blog post summarizes a few approaches you can take to cleanly map or rewrite URLs with ASP.NET, and have the option to structure the URLs of your application however you want. Why does URL mapping and rewriting matter? The most common scenarios where developers want greater flexibility with URLs are: 1) Handling cases where you want to restructure the pages within your web application, and you want to ensure that people who have bookmarked old URLs don't break when you move pages around. Url-rewriting enables you to transparently forward requests to the new page location without breaking browsers. 2) Improving the search relevancy of pages on your site with search engines like Google, Yahoo and Live. Specifically, URL Rewriting can often make it easier to embed common keywords into the URLs of the pages on your sites, which can often increase the chance of someone clicking your link. Moving from using querystring arguments to instead use fully qualified URL's can also in some cases increase your priority in search engine results. Using techniques that force referring links to use the same case and URL entrypoint (for example: weblogs.asp.net/scottgu instead of weblogs.asp.net/scottgu/default.aspx) can also avoid diluting your pagerank across multiple URLs, and increase your search results. In a world where search engines increasingly drive traffic to sites, extracting any little improvement in your page ranking can yield very good ROI to your business. Increasingly this is driving developers to use URL-Rewriting and other SEO (search engine optimization) techniques to optimize sites (note that SEO is a fast moving space, and the recommendations for increasing your search relevancy evolve monthly). For a list of some good search engine optimization suggestions, I'd recommend reading the SSW Rules to Better Google Rankings, as well as MarketPosition's article on how URLs can affect top search engine ranking. Sample URL Rewriting Scenario For the purpose of this blog post, I'm going to assume we are building a set of e-commerce catalog pages within an application, and that the products are organized by categories (for example: books, videos, CDs, DVDs, etc). Let's assume that we initially have a page called "Products.aspx" that takes a category name as a querystring argument, and filters the products accordingly. The corresponding URLs to this Products.aspx page look like this: http://www.store.com/products.aspx?category=bookshttp://www.store.com/products.aspx?category=DVDshttp://www.store.com/products.aspx?category=CDs Rather than use a querystring to expose each category, we want to modify the application so that each product category looks like a unique URL to a search engine, and has the category keyword embedded in the actual URL (and not as a querystring argument). We'll spend the rest of this blog post going over 4 different approaches that we could take to achieve this. Approach 1: Use Request.PathInfo Parameters Instead of QueryStrings The first approach I'm going to demonstrate doesn't use Url-Rewriting at all, and instead uses a little-known feature of ASP.NET - the Request.PathInfo property. To help explain the usefulness of this property, consider the below URL scenario for our e-commerce store: http://www.store.com/products.aspx/Bookshttp://www.store.com/products.aspx/DVDshttp://www.store.com/products.aspx/CDs One thing you'll notice with the above URLs is that they no longer have Querystring values - instead the category parameter value is appended on to the URL as a trailing /param value after the Products.aspx page handler name. An automated search engine crawler will then interpret these URLs as three different URLs, and not as one URL with three different input values (search engines ignore the filename extension and just treat it as another character within the URL). You might wonder how you handle this appended parameter scenario within ASP.NET. The good news is that it is pretty simple. Simply use the Request.PathInfo property, which will return the content immediately following the products.aspx portion of the URL. So for the above URLs, Request.PathInfo would return "/Books", "/DVDs", and "/CDs" (in case you are wondering, the Request.Path property would return "/products.aspx"). You could then easily write a function to retrieve the category like so (the below function strips out the leading slash and returning just "Books", "DVDs" or "CDs"): Function GetCategory() As String If (Request.PathInfo.Length = 0) Then Return "" Else Return Request.PathInfo.Substring(1) End If End Function Sample Download: A sample application that I've built that shows using this technique can be downloaded here. What is nice about this sample and technique is that no server configuration changes are required in order to deploy an ASP.NET application using this approach. It will also work fine in a shared hosting environment. Approach 2: Using an HttpModule to Perform URL Rewriting An alternative approach to the above Request.PathInfo technique would be to take advantage of the HttpContext.RewritePath() method that ASP.NET provides. This method allows a developer to dynamically rewrite the processing path of an incoming URL, and for ASP.NET to then continue executing the request using the newly re-written path. For example, we could choose to expose the following URLs to the public: http://www.store.com/products/Books.aspxhttp://www.store.com/products/DVDs.aspxhttp://www.store.com/products/CDs.aspx This looks to the outside world like there are three separate pages on the site (and will look great to a search crawler). By using the HttpContext.RewritePath() method we can dynamically re-write the incoming URLs when they first reach the server to instead call a single Products.aspx page that takes the category name as a Querystring or PathInfo parameter instead. For example, we could use an an Application_BeginRequest event in Global.asax like so to do this: void Application_BeginRequest(object sender, EventArgs e) { string fullOrigionalpath = Request.Url.ToString(); if (fullOrigionalpath.Contains("/Products/Books.aspx")) { Context.RewritePath("/Products.aspx?Category=Books"); } else if (fullOrigionalpath.Contains("/Products/DVDs.aspx")) { Context.RewritePath("/Products.aspx?Category=DVDs"); } } The downside of manually writing code like above is that it can be tedious and error prone. Rather than do it yourself, I'd recommend using one of the already built HttpModules available on the web for free to perform this work for you. Here a few free ones that you can download and use today: UrlRewriter.net UrlRewriting.net These modules allow you to declaratively express matching rules within your application's web.config file. For example, to use the UrlRewriter.Net module within your application's web.config file to map the above URLs to a single Products.aspx page, we could simply add this web.config file to our application (no code is required): <?xml version="1.0"?><configuration> <configSections> <section name="rewriter" requirePermission="false" type="Intelligencia.UrlRewriter.Configuration.RewriterConfigurationSectionHandler, Intelligencia.UrlRewriter" /> </configSections> <system.web> <httpModules> <add name="UrlRewriter" type="Intelligencia.UrlRewriter.RewriterHttpModule, Intelligencia.UrlRewriter"/> </httpModules> </system.web> <rewriter> <rewrite url="~/products/books.aspx" to="~/products.aspx?category=books" /> <rewrite url="~/products/CDs.aspx" to="~/products.aspx?category=CDs" /> <rewrite url="~/products/DVDs.aspx" to="~/products.aspx?category=DVDs" /> </rewriter> </configuration> The HttpModule URL rewriters above also add support for regular expression and URL pattern matching (to avoid you having to hard-code every URL in your web.config file). So instead of hard-coding the category list, you could re-write the rules like below to dynamically pull the category from the URL for any "/products/[category].aspx" combination: <rewriter> <rewrite url="~/products/(.+).aspx" to="~/products.aspx?category=$1" /> </rewriter> This makes your code much cleaner and super extensible. Sample Download: A sample application that I've built that shows using this technique with the UrlRewriter.Net module can be downloaded here. What is nice about this sample and technique is that no server configuration changes are required in order to deploy an ASP.NET application using this approach. It will also work fine in a medium trust shared hosting environment (just ftp/xcopy to the remote server and you are good to go - no installation required). Approach 3: Using an HttpModule to Perform Extension-Less URL Rewriting with IIS7 The above HttpModule approach works great for scenarios where the URL you are re-writing has a .aspx extension, or another file extension that is configured to be processed by ASP.NET. When you do this no custom server configuration is required - you can just copy your web application up to a remote server and it will work fine. There are times, though, when you want the URL to re-write to either have a non-ASP.NET file extension (for example: .jpg, .gif, or .htm) or no file-extension at all. For example, we might want to expose these URLs as our public catalog pages (note they have no .aspx extension): http://www.store.com/products/Bookshttp://www.store.com/products/DVDshttp://www.store.com/products/CDs With IIS5 and IIS6, processing the above URLs using ASP.NET is not super easy. IIS 5/6 makes it hard to perform URL rewriting on these types of URLs within ISAPI Extensions (which is how ASP.NET is implemented). Instead you need to perform the rewriting earlier in the IIS request pipeline using an ISAPI Filter. I'll show how to-do this on IIS5/6 in the Approach 4 section below. The good news, though, is that IIS 7.0 makes handling these types of scenarios super easy. You can now have an HttpModule execute anywhere within the IIS request pipeline - which means you can use the URLRewriter module above to process and rewrite extension-less URLs (or even URLs with a .asp, .php, or .jsp extension). Below is how you would configure this with IIS7: <?xml version="1.0" encoding="UTF-8"?><configuration> <configSections> <section name="rewriter" requirePermission="false" type="Intelligencia.UrlRewriter.Configuration.RewriterConfigurationSectionHandler, Intelligencia.UrlRewriter" /> </configSections> <system.web> <httpModules> <add name="UrlRewriter" type="Intelligencia.UrlRewriter.RewriterHttpModule, Intelligencia.UrlRewriter" /> </httpModules> </system.web> <system.webServer> <modules runAllManagedModulesForAllRequests="true"> <add name="UrlRewriter" type="Intelligencia.UrlRewriter.RewriterHttpModule" /> </modules> <validation validateIntegratedModeConfiguration="false" /> </system.webServer> <rewriter> <rewrite url="~/products/(.+)" to="~/products.aspx?category=$1" /> </rewriter> </configuration> Note the "runAllManagedModulesForAllRequests" attribute that is set to true on the <modules> section within <system.webServer>. This will ensure that the UrlRewriter.Net module from Intelligencia, which was written before IIS7 shipped, will be called and have a chance to re-write all URL requests to the server (including for folders). What is really cool about the above web.config file is that: 1) It will work on any IIS 7.0 machine. You don't need an administrator to enable anything on the remote host. It will also work in medium trust shared hosting scenarios. 2) Because I've configured the UrlRewriter in both the <httpModules> and IIS7 <modules> section, I can use the same URL Rewriting rules for both the built-in VS web-server (aka Cassini) as well as on IIS7. Both fully support extension-less URLRewriting. This makes testing and development really easy. IIS 7.0 server will ship later this year as part of Windows Longhorn Server, and will support a go-live license with the Beta3 release in a few weeks. Because of all the new hosting features that have been added to IIS7, we expect hosters to start aggressively offering IIS7 accounts relatively quickly - which means you should be able to start to take advantage of the above extension-less rewriting support soon. We'll also be shipping a Microsoft supported URL-Rewriting module in the IIS7 RTM timeframe that will be available for free as well that you'll be able to use on IIS7, and which will provide nice support for advanced re-writing scenarios for all content on your web-server. Sample Download: A sample application that I've built that shows using this extension-less URL technique with IIS7 and the UrlRewriter.Net module can be downloaded here. Approach 4: ISAPIRewrite to enable Extension-less URL Rewriting for IIS5 and IIS6 If you don't want to wait for IIS 7.0 in order to take advantage of extension-less URL Rewriting, then your best best is to use an ISAPI Filter in order to re-write URLs. There are two ISAPI Filter solutions that I'm aware of that you might want to check-out: Helicon Tech's ISAPI Rewrite: They provide an ISAPI Rewrite full product version for $99 (with 30 day free trial), as well as a ISAPI Rewrite lite edition that is free. Ionic's ISAPI Rewrite: This is a free download (both source and binary available) I actually don't have any first-hand experience using either of the above solutions - although I've heard good things about them. Scott Hanselman and Jeff Atwood recently both wrote up great blog posts about their experiences using them, and also provided some samples of how to configure the rules for them. The rules for Helicon Tech's ISAPI Rewrite use the same syntax as Apache's mod_rewrite. For example (taken from Jeff's blog post): [ISAPI_Rewrite]# fix missing slash on folders# note, this assumes we have no folders with periods!RewriteCond Host: (.*)RewriteRule ([^.?]+[^.?/]) http\://$1$2/ [RP]# remove index pages from URLsRewriteRule (.*)/default.htm$ $1/ [I,RP]RewriteRule (.*)/default.aspx$ $1/ [I,RP]RewriteRule (.*)/index.htm$ $1/ [I,RP]RewriteRule (.*)/index.html$ $1/ [I,RP]# force proper www. prefix on all requestsRewriteCond %HTTP_HOST ^test\.com [I]RewriteRule ^/(.*) http://www.test.com/$1 [RP]# only allow whitelisted referers to hotlink imagesRewriteCond Referer: (?!http://(?:www\.good\.com|www\.better\.com)).+RewriteRule .*\.(?:gif|jpg|jpeg|png) /images/block.jpg [I,O] Definitely check out Scott's post and Jeff's post to learn more about these ISAPI modules, and what you can do with them. Note: One downside to using an ISAPI filter is that shared hosting environments typically won't allow you to install this component, and so you'll need either a virtual dedicated hosting server or a dedicated hosting server to use them. But, if you do have a hosting plan that allows you to install the ISAPI, it will provide maximum flexibility on IIS5/6 - and tide you over until IIS7 ships. Handling ASP.NET PostBacks with URL Rewriting One gotcha that people often run into when using ASP.NET and Url-Rewriting has to-do with handling postback scenarios. Specifically, when you place a <form runat="server"> control on a page, ASP.NET will automatically by default output the "action" attribute of the markup to point back to the page it is on. The problem when using URL-Rewriting is that the URL that the <form> control renders is not the original URL of the request (for example: /products/books), but rather the re-written one (for example: /products.aspx?category=books). This means that when you do a postback to the server, the URL will not be your nice clean one. With ASP.NET 1.0 and 1.1, people often resorted to sub-classing the <form> control and created their own control that correctly output the action to use. While this works, it ends up being a little messy - since it means you have to update all of your pages to use this alternate form control, and it can sometimes have problems with the Visual Studio WYSIWYG designer. The good news is that with ASP.NET 2.0, there is a cleaner trick that you can use to rewrite the "action" attribute on the <form> control. Specifically, you can take advantage of the new ASP.NET 2.0 Control Adapter extensibility architecture to customize the rendering of the <form> control, and override its "action" attribute value with a value you provide. This doesn't require you to change any code in your .aspx pages. Instead, just add a .browser file to your /app_browsers folder that registers a Control Adapter class to use to output the new "action" attribute: You can see a sample implementation I created that shows how to implement a Form Control Adapter that works with URLRewriting in my sample here. It works for both the Request.PathInfo and UrlRewriter.Net module approaches I used in Approach 1 and 2 above, and uses the Request.RawUrl property to retrieve the original, un-rewritten, URL to render. With the ISAPIRewrite filter in Approach 4 you can retrieve the Request.ServerVariables["HTTP_X_REWRITE_URL"] value that the ISAPI filter uses to save the original URL instead. My FormRewriter class implementation above should work for both standard ASP.NET and ASP.NET AJAX 1.0 pages (let me know if you run into any issues). Handling CSS and Image Reference Correctly One gotcha that people sometime run into when using Url Rewriting for the very first time is that they find that their image and CSS stylesheet references sometimes seem to stop working. This is because they have relative references to these files within their HTML pages - and when you start to re-write URLs within an application you need to be aware that the browser will often be requesting files in different logical hierarchy levels than what is really stored on the server. For example, if our /products.aspx page above had a relative reference to "logo.jpg" in the .aspx page, but was requested via the /products/books.aspx url, then the browser will send a request for /products/logo.jpg instead of /logo.jpg when it renders the page. To reference this file correctly, make sure you root qualify CSS and Image references ("/style.css" instead of "style.css"). For ASP.NET controls, you can also use the ~ syntax to reference files from the root of the application (for example: <asp:image imageurl="~/images/logo.jpg" runat="server"/> Hope this helps, Scott P.S. For more ASP.NET 2.0 Tips and Tricks, please check out my ASP.NET 2.0 Tips, Tricks and Tutorials Page. P.P.S. Special thanks to Scott Hanselman and Michael K. Campbell for testing my Form Control Adapter with their sites. |
| |
|
| |
| |
One of my goals this year is to use video more with my blog. My theory is that video is often a better medium than text to walkthrough how something works, and can also help you avoid the tedium of reading though some of my really long blog posts... :-) Over the next few months I'm going to try and create a new video every other week or so on various topics. Many of these videos are going to involve first looks at some of the new features coming with Visual Studio "Orcas", which is our new release that will ship later this year. For today's video I decided to focus on introducing LINQ - which I think is one of the most exciting features coming with "Orcas". At a high-level, LINQ makes the concept of query a first class programming concept within .NET. Using LINQ you can easily query relational databases, XML files, as well as any plain-old .NET object. You can also easily use your own data source abstractions with LINQ to provide rich domain models for various data providers (for a great example of this check out Fabrice's LINQ to Amazon implementation that supports LINQ queries against Amazon data exposed via web-services). Both VB and C# include rich language integration with LINQ as part of the "Orcas" release, including full intellisense, compile-time checking, and debugging support. Watch or Download the Video This first video starts with a new project, and then demonstrates the basics of using LINQ against a SQL Database to build a simple data reporting page (including support for aggregate values computed from multiple tables, and efficient server-side paging within the database). You can watch the video online here (it is 24 minutes in length). Or you can download a .zip version of it here if you want to save and watch it locally. Note that it might take 30-60 seconds to buffer (since it is a large video). In the event that my server is swamped with requests, I'll update the location and post it on one of the Microsoft video servers later this week. For more information on LINQ (including the slide deck for a "Building ASP.NET Data Driven Application Using LINQ" talk of mine), please check out my previous post here. For other ASP.NET 2.0 Tips, Tricks and Tutorials please check out my ASP.NET Tips and Tricks summary listing page. Specifics Topics Covered in this Video My walkthrough in this video illustrates a number of new features: 1) A brief demonstration of some of the new WYSIWYG HTML designer capabilities (including split-view and a brief look at the new CSS manager - both of which I'll cover in more detail in the future in a separate video): 2) How to create classes that model data using the new VS "Orcas" ORM designer for LINQ to SQL: 3) How to use the new LINQ intellisense support within the VS "Orcas" code editor to get full intellisense and compilation support for queries: 4) How to use LINQ to SQL to create a data report that combines Product entity data with aggregate unit and revenue values computed from OrderDetail entities associated with the Product entities. This data report uses server side database paging to efficiently retrieve only 10 rows of data at a time (so that with a 100,000 row products table you only ever retrieve 10 rows of data from the database regardless of which page index you are on within a report): Future Videos I'll be drilling into LINQ some more with future videos (I barely scratched the surface with this one). Additional segments will include content on: Type inference and the "var" keyword (and why that is so cool) Supporting Insert, Update and Deletes scenarios using LINQ to SQL Validation rules and logic within LINQ Data Models Using SPROCs with LINQ to SQL Richer JOIN support with LINQ to SQL LINQ to XML and LINQ to Objects Using the new LINQDataSource controls and other ASP.NET Data Controls to easily create Web UI with LINQ I'll also obviously have many more ASP.NET and web-related video topics to cover including: The new HTML WYSIWYG Designer and CSS support Client-JavaScript Intellisense JavaScript Debugging ASP.NET AJAX Extender Support Database Dump and Upload Integration Unit Testing Multi-targeting support (showing how you can use VS "Orcas" to build ASP.NET 2.0 projects - without having to upgrade your framework/server) Hope this helps, Scott P.S. If you have other topics and/or subjects you'd like me to drill in on with videos, please post them in the comments section of this post. |
| |
|
| |
| |
Keywords are one of the main factors that affect Search Engine Ranking Positions. Optimizing your site with the right keyword will give you great results. Analyze your competitors site for your targeted keyword and check what theyve done that carried them on top. |
| |
|
| |
Related Pages
|
|
|
Related Companies
|
| |
|
|
|