Latest Entries »

ASP.Net includes quite a plethora of properties to retrieve path information about the current request, control and application. There’s a ton of information available about paths on the Request object, some of it appearing to overlap and some of it buried several levels down, and it can be confusing to find just the right path that you are looking for.

To keep things straight I thought it’d be a good idea to summarize those options briefly along with describing some common scenarios of how they might be used.

Here’s a list of the Path related properties on the Request object (and the Page object):

Request Property

Function and Example

ApplicationPath

Returns the a Web server relative path to your application root

/WestwindWebStore/

PhysicalApplicationPath

Returns a local file system path to your application root

D:\inetpub\wwwroot\WestWindWebStore\

PhysicalPath

Returns the full file system path to the currently executing script

D:\inetpub\wwwroot\WestWindWebStore\Item.aspx

CurrentExecutionFilePath

FilePath

Path

In most situations all of these return the virtual path to the currently executing script relative to the Web Server root.

/WestwindWebStore/item.aspx

PathInfo

Returns any extra path following the script name. Rarely used – this value is usually blank.

/WestwindWebStore/item.aspx/ExtraPathInfo

RawUrl

Returns the application relative URL including querystring or pathinfo

/WestwindWebStore/item.aspx?sku=WWHELP30

Url

Returns the fully qualified URL including domain and protocol

http://www.west-wind.com/Webstore/item.aspx?sku=WWHELP30

Page.TemplateSourceDirectory

Control.TemplateSourceDirectory

Returns the virtual path of the currently executing control (or page). Very useful if you need to know the location of your ASCX control instead of the location of the page.

/WestwindWebStore/admin

Note though that there is nothing that returns to you just the name of the virtual path of the current page without the script name, which to me seems strange. I would expect Path to do this but instead you’ll have to strip of the script name:

string VirtualPath = Request.Path.Substring(0,Request.Path.LastIndexOf(“/”)+1 );

Between these settings you can get all the information you may need to figure out where you are at and to build new Url if necessary. If you need to build a URL completely from scratch you may need a few more: Server Variables:

Server Variable

Function and Example

SERVER_NAME

The name of the domain or IP address

SERVER_PORT

The port that the request runs under – if other than 80 you’ll have to build that into the URL

SERVER_PORT_SECURE

Determines whether https: was used

If you’re building a URL from scratch you might use something like this:

string Port = Request.ServerVariables["SERVER_PORT"];

if (Port == null || Port == “80″ || Port == “443″)

Port = “”;

else

Port = “:” + Port;

string Protocol = Request.ServerVariables["SERVER_PORT_SECURE"];

if (Protocol == null || Protocol == “0″)

Protocol = “http://”;

else

Protocol = “https://”;

// *** Figure out the base Url which points at the application’s root

this.BasePath = Protocol + Request.ServerVariables["SERVER_NAME"] +

Port + Request.ApplicationPath;

From there you can add Request.QueryString etc. as needed. But in most situations it might just be easier to use the Request.Url and manipulate the string the way you need to to get the path. Watch out for the URL not always returning port information though!

Relative Paths and Server Controls

The most common use for those variables above is to get the application base path to create relative URLS. If you’ve ever built user controls I’m sure you will have found out the hassles that go with relative paths for images or stylesheets if you move the User or custom Server Control into a different directory. For components you always need to build off this base path and then append the relative path to links as necessary.

Note that ASP.Net’s internal controls all support the ~ as an Application base path designator whereever you can provide a link. For example in the Image Control you can say:

MyImage.ImageUrl = “~/images/stop.gif”;

which will always load the image out of the application’s images directory regardless where the current page lives. If you create controls that require paths you should also always support this convention. It’s pretty easy to implement with code like this:

///

/// Fixes up URLs that include the ~ starting character and expanding
/// to a full server relative path

///

///

the URL to fix up

public static string FixupUrl(string Url)

{

if (Url.StartsWith(“~”) )

return (HttpContext.Current.Request.ApplicationPath +
Url.Substring(1)).Replace(“//”,“/”);

return Url;

}

You can also use Control.ResolveUrl() which returns a fully qualified URL from a partial or relative path.

Source : http://west-wind.com/weblog/posts/269.aspx

I was a little confused about the difference between <%= expression %> and <%# expression %> in ASP.NET. It seems like both work in a lot of cases, but in other cases, only the # (data binding) version works. So, I decided to dig into it a little bit. To try it out I built this simple page:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <p>Equals: <%= this.TestValue %></p>
        <p>Pound: <%# this.TestValue %></p>
        <p>Equals label: <asp:Label runat="server" ID="_equals" Text="<%= this.TestValue %>" /></p>
        <p>Pound label: <asp:Label runat="server" ID="_pound" Text="<%# this.TestValue %>" /></p>
    </div>
    </form>
</body>
</html>

And the code behind is:

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        _testValue = "2";
    }

    protected void Page_PreRenderComplete(object sender, EventArgs e)
    {
        // DataBind();
        _testValue = "3";
    }

    public string TestValue
    {
        get { return _testValue; }
    }

    private string _testValue = "1";
}

Here’s what the result is when the DataBind() line is commented out:

Equals: 3

Pound:

Equals label:

Pound label:

And, when it’s not commented out:

Equals: 3

Pound: 2

Equals label:

Pound label: 2

At first glance it looks like the Equals label case did nothing. But, if you view source, you see:

<p>Equals label: <span id=”_equals”><%= this.TestValue %></span></p>

The literal expression made it down to the browser and it’s just invalid HTML. What you can see as a result is:

  • The <%= expressions are evaluated at render time
  • The <%# expressions are evaluated at DataBind() time and are not evaluated at all if DataBind() is not called.
  • <%# expressions can be used as properties in server-side controls. <%= expressions cannot.

Now, let’s look at the generated code to see how it works. It builds the control tree using the following code:

        private void @__BuildControlTree(default_aspx @__ctrl) {
            this.InitializeCulture();

            System.Web.UI.IParserAccessor @__parser = ((System.Web.UI.IParserAccessor)(@__ctrl));
            @__parser.AddParsedSubObject(new
                        System.Web.UI.LiteralControl("\r\n\r\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3" +
                        ".org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\r\n\r\n<html xmlns=\"http://www.w3.org/1" +
                        "999/xhtml\" >\r\n"));

            global::System.Web.UI.HtmlControls.HtmlHead @__ctrl1;
            @__ctrl1 = this.@__BuildControl__control2();
            @__parser.AddParsedSubObject(@__ctrl1);
            @__parser.AddParsedSubObject(new System.Web.UI.LiteralControl("\r\n<body>\r\n    "));

            global::System.Web.UI.HtmlControls.HtmlForm @__ctrl2;
            @__ctrl2 = this.@__BuildControlform1();
            @__parser.AddParsedSubObject(@__ctrl2);

            @__parser.AddParsedSubObject(new System.Web.UI.LiteralControl("\r\n</body>\r\n</html>\r\n"));
        }

@__BuildControl__control2() isn’t that intersting, it’s just the <head> stuff. The guts are in @__BuildControlform1():

        private global::System.Web.UI.HtmlControls.HtmlForm @__BuildControlform1() {
            global::System.Web.UI.HtmlControls.HtmlForm @__ctrl;
            @__ctrl = new global::System.Web.UI.HtmlControls.HtmlForm();
            this.form1 = @__ctrl;
            @__ctrl.ID = "form1";

            global::System.Web.UI.DataBoundLiteralControl @__ctrl1;
            @__ctrl1 = this.@__BuildControl__control4();
            System.Web.UI.IParserAccessor @__parser = ((System.Web.UI.IParserAccessor)(@__ctrl));
            @__parser.AddParsedSubObject(@__ctrl1);

            global::System.Web.UI.WebControls.Label @__ctrl2;
            @__ctrl2 = this.@__BuildControl_equals();
            @__parser.AddParsedSubObject(@__ctrl2);

            global::System.Web.UI.WebControls.Label @__ctrl3;
            @__ctrl3 = this.@__BuildControl_pound();
            @__parser.AddParsedSubObject(@__ctrl3);

            @__ctrl.SetRenderMethodDelegate(new System.Web.UI.RenderMethod(this.@__Renderform1));
            return @__ctrl;
        }

This is building all of the controls in the form. First let’s look at the control built with @__BuildControl__control4():

        private global::System.Web.UI.DataBoundLiteralControl @__BuildControl__control4() {
            global::System.Web.UI.DataBoundLiteralControl @__ctrl;

            @__ctrl = new global::System.Web.UI.DataBoundLiteralControl(2, 1);
            @__ctrl.SetStaticString(0, "</p>\r\n        <p>Pound: ");
            @__ctrl.SetStaticString(1, "</p>\r\n        <p>Equals label: ");
            @__ctrl.DataBinding += new System.EventHandler(this.@__DataBind__control4);

            return @__ctrl;
        }

And related to this is:

        public void @__DataBind__control4(object sender, System.EventArgs e) {
            System.Web.UI.Page Container;
            System.Web.UI.DataBoundLiteralControl target;

            target = ((System.Web.UI.DataBoundLiteralControl)(sender));
            Container = ((System.Web.UI.Page)(target.BindingContainer));
            target.SetDataBoundString(0, System.Convert.ToString(this.TestValue, System.Globalization.CultureInfo.CurrentCulture));
        }

This is the part of the page up to the first <%#. You can see that it uses a DataBoundLiteralControl which is divided between static strings and data bound strings. When DataBind is called on the page, the event handler is called and SetDataBoundString is called on the control. This is why the value is captured at bind time. If you want to see how DataBoundLiteralControl works, you can use .NET Reflector. You can see that it’s Render function looks like:

    protected internal override void Render(HtmlTextWriter output)
    {
        int num1 = this._dataBoundLiteral.Length;
        for (int num2 = 0; num2 < this._staticLiterals.Length; num2++)
        {
            if (this._staticLiterals[num2] != null)
            {
                output.Write(this._staticLiterals[num2]);
            }
            if ((num2 < num1) && (this._dataBoundLiteral[num2] != null))
            {
                output.Write(this._dataBoundLiteral[num2]);
            }
        }
    }

So, it basically outputs the static and data bound fields alternately. That’s how it renders the first <%# value on the page if DataBind() is called. Next, let’s look at the “_equals” control:

        private global::System.Web.UI.WebControls.Label @__BuildControl_equals() {
            global::System.Web.UI.WebControls.Label @__ctrl;

            @__ctrl = new global::System.Web.UI.WebControls.Label();
            @__ctrl.ApplyStyleSheetSkin(this);
            @__ctrl.ID = "_equals";
            @__ctrl.Text = "<%= this.TestValue %>";

            return @__ctrl;
        }

You can see that the <%= is not in any way special. It’s just literal text. The “_pound” control, which uses <%# on the other hand, looks like:

        private global::System.Web.UI.WebControls.Label @__BuildControl_pound() {
            global::System.Web.UI.WebControls.Label @__ctrl;

            @__ctrl = new global::System.Web.UI.WebControls.Label();
            @__ctrl.ApplyStyleSheetSkin(this);
            @__ctrl.ID = "_pound";
            @__ctrl.DataBinding += new System.EventHandler(this.@__DataBinding_pound);

            return @__ctrl;
        }

        public void @__DataBinding_pound(object sender, System.EventArgs e) {
            System.Web.UI.WebControls.Label dataBindingExpressionBuilderTarget;
            System.Web.UI.Page Container;
            dataBindingExpressionBuilderTarget = ((System.Web.UI.WebControls.Label)(sender));
            Container = ((System.Web.UI.Page)(dataBindingExpressionBuilderTarget.BindingContainer));

            dataBindingExpressionBuilderTarget.Text = System.Convert.ToString( this.TestValue , System.Globalization.CultureInfo.CurrentCulture);
        }

As compared to the <%= version, <%# is treated specially in parameters. It adds a data binding handler and sets the property at data bind time. That’s why <%# does work in parameters and why it picks up the value at data bind time.

So, how does the first <%= work? We can see this by looking at the following function:

        private void @__Renderform1(System.Web.UI.HtmlTextWriter @__w, System.Web.UI.Control parameterContainer) {
            @__w.Write("        <p>Equals: ");
            @__w.Write( this.TestValue );

            parameterContainer.Controls[0].RenderControl(@__w);
            parameterContainer.Controls[1].RenderControl(@__w);
            @__w.Write("</p>\r\n        <p>Pound label: ");
            parameterContainer.Controls[2].RenderControl(@__w);
            @__w.Write("</p>\r\n    </div>\r\n    ");
        }

Here we can see the @__w.Write(this.TestValue) line which is the result of the <%= line in the source. It’s outputting the value of this.TestValue at render time, which explains the behavior we saw.

So, it all makes sense to me now. I hope it makes sense to you too :-)

Original Post : http://blogs.msdn.com/b/dancre/archive/2007/02/13/the-difference-between-lt-and-lt-in-asp-net.aspx

Thông thường khi lưu dữ liệu vào SQL ta thường lưu dưới dạng Ngày tháng kèm theo thời gian đầy đủ. Trong một số trường hợp chỉ cần lấy Ngày Tháng Năm trong cột dữ liệu này để so sánh thì chỉ cần dùng hàm được xây dựng sẵn trong SQL như sau

SELECT CONVERT(VARCHAR(10),GETDATE(),103)

Với  GetDate() là hàm lấy ngày tháng trong SQL, bạn có thể thay thế bằng cột chứa ngày tháng của bạn trong table vd :

SELECT   (CONVERT(VARCHAR(10),NgayThangCollum,103)    FROM    YourTable

Tham số 103 là kiểu ngày tháng theo từng quốc gia, 103 ở trên là kiểu ngày tháng dd/mm/yy mà Việt Nam mình đang dùng :)

Trên đây chỉ đơn giản là cách lấy ngày tháng không kèm thời gian, để lấy dữ liệu theo một ngày tháng nhất định nào đó bạn có thể dùng sql query như sau :

SELECT    *    FROM    yourTable

where ((CONVERT(VARCHAR(10),VisitDate ,103)) like  ‘dd/mm/yy’)

Hoặc dùng biến ngày tháng kiểu string dạng short date string

@YourDate varchar(10)

SELECT    *    FROM    yourTable

where ((CONVERT(VARCHAR(10),VisitDate ,103)) like  @YourDate)

Chúc thành công :)

link tham khảo :

http://blog.sqlauthority.com/2007/06/10/sql-server-retrieve-select-only-date-part-from-datetime-best-practice/

http://msdn.microsoft.com/en-us/library/ms187928.aspx




using System.Security.Principal;

Code :

IPrincipal user = this.Page.User;

if (User.IsInRole(“administrator”))

{

// do anything

}

IndexReader r = IndexReader.Open(path-to-index-folder);
DataTable dt = new DataTable();
dt.Columns.Add(IndexedFields.ID, typeof(string));
int num = r.NumDocs();
for (int i = 0; i < num; i++)
{
if (!r.IsDeleted(i))
{
Document d = r.Document(i);
DataRow row = dt.NewRow();
row[IndexedFields.ID] = d.Get(IndexedFields.ID);
dt.Rows.Add(row);
}
}
r.Close();

foreach (DataRow dr in dt.Rows)
{
string id = dr["ID"].ToString();
//do what you want
}

This post is about the full-text search engine Lucene.NET and how I integrated it into BugTracker.NET .   If you are thinking of adding full-text search to your application, you might find this post useful.  I’m not saying this is THE way of using Lucene.NET, but it is an example of ONE way.
Lucene.NET is a C# port of the original Lucene , an Apache Foundation open source project, written in java.

Why did I use Lucene.NET instead of the SQL Server full-text search engine?  Well, I’d like to say that I did some research into the pros and cons of the two choices, but actually I didn’t do any comparative research.  What happened was that during a Stackoverflow podcast I heard Joel Spolsky mention that FogBugz uses Lucene as its engine and that he was happy with it.   I trust him, and  I was curious, so, one weekend I downloaded Lucene.NET and played with it a bit and before the weekend was over I was already done integrating it into BugTracker.NET.   I never looked at the SQL Server alternative at all, so I can’t tell you anything about it.

Lucene itself is a class library, not an executable.   You call Lucene functions to do the search.  There is an open source standalone server built on Lucene called Solr .   You send Solr messages to do the search.  One way of using Lucene would have been to have my users run Solr side-by-side with SQL Server.   As with SQL Server full-text search, I can’t tell you anything about Solr because I didn’t try it.   It wouldn’t have made sense to use Solr for BugTracker.NET, I think, because Solr would have been an additional installation hassle.   And running a server wouldn’t have been doable at all at a cheap shared host like GoDaddy, where my own BugTracker.NET demo lives.    So, instead of using Solr, I used the Lucene class libraries directly.

To integrate Lucene, I had to build the following, which I list here and then describe in more detail below.

1) How Lucene would build its searchable index. Lucene doesn’t search my SQL Server database directly.   Instead, it searches its own “database”, its own index.
2) The design of the Lucene index
3) How I would update Lucene’s index whenever data in my database changes.
4) Sending the search query to Lucene.
5) Displaying the results.

Now the details.  I’ve simplied my code for this post, so that you can more easily see the overall design and understand the concepts and my design choices.

1) Building the index.

When an ASP.NET application receives its first HTTP request after having been shut down, the Application_OnStart event fires, which I handle in Global.asax.   I call my “build_lucene_index” method.    Notice that I have a configuration setting “EnableLucene”.    I was nervous about the my understanding of Lucene and whether my way of using it was the right architecture, and so I wanted to make sure I gave my users a way of turning Lucene off in case it was causing trouble.    More on that in a bit.

For a really big database, you wouldn’t want to necessarily build the search index from scratch over and over, but I’m counting on BugTracker.NET databases being on the small side.   Is that a safe assumption?  A bug database shouldn’t be that big or else you’re doing it wrong, right?

public void Application_OnStart(Object sender, EventArgs e)
{
if (btnet.Util.get_setting(“EnableLucene”, ”1″) == ”1″)
{
build_lucene_index(this.Application);
}
}
The build_lucene_index method starts a new worker thread, where the real work is done.

public static void build_lucene_index(System.Web.HttpApplicationState app)
{
System.Threading.Thread thread = new System.Threading.Thread(threadproc_build);
thread.Start(app);
}

The worker thread first grabs a lock so that it can build the index without being disturbed by other threads.   The other threads would be the result of users either searching or users updating text, triggering a modification to Lucene’s index.    I don’t want those threads to be dealing with a partially built index, so I make those threads wait for the one-and-only lock.

My way of handling multithreading was one of the things that I was nervous about.   I feared some sort of hard-to-reproduce deadlock condition, or race condition, but so far, there have been no reports from BugTracker.NET users of any trouble, so I my design appears to be solid.

To create the index, I create a Lucene “IndexWriter”.   I run a SQL query against my database to fetch the text I want to be able to search and the database keys that go with that text.   Then I loop through the query results adding a Lucene “Document” for each row.   Actually, in my real code, I get the searchable text from several different fields in my database, but in the snippet below I have simplified my harvesting of text from my database.

Lucene.Net.Analysis.Standard.StandardAnalyzer analyzer = new Lucene.Net.Analysis.Standard.StandardAnalyzer();

static void threadproc_build(object obj)
{
lock (my_lock)
{
try
{

Lucene.Net.Index.IndexWriter writer = new Lucene.Net.Index.IndexWriter(“c:\\folder_where_lucene_index_lives”, analyzer , true);

DataSet ds = btnet.DbUtil.get_dataset(“select bug_id, bug_text from bugs”)

foreach (DataRow dr in ds.Tables[0].Rows)
{
writer.AddDocument(create_doc(
(int)dr["bug_id"],
(string)dr["bug_text"]));
}

writer.Optimize();
writer.Close();
}
catch (Exception e)
{
btnet.Util.write_to_log(“exception building Lucene index: ” + e.Message);
}
}
}

2) The design of the Lucene Index

Here’s where I create a Lucene “Document”.    An index contains a list of documents.   A doc has fields that you define.   My doc shown here has three fields.   The first field “text” is what Lucene will analyze and index, the searchable text.  The second field is the key I will use to link the Lucene data to the rows in my database.   Notice I tell Lucene that this key should be UN_TOKENIZED, stored as is.   That’s all you need for a minimal Lucene doc, a key for you and some text to search on for Lucene.  The third field in my example is the text again, but this time, UN_TOKENIZED, stored as is.  I will use that text for having Lucene highlight in my results page the snippets where the hits are.   More on highlighting later.

One of the decisions you’ll have to make when using Lucene is what text to index and how to package it for Lucene.    In my database, the text doesn’t just live in one field.    A bug has a short text description, a list of comments, a list of incoming and outgoing emails, and even Digg-style tags.   In my real code as opposed to the snippets here,  I fetch text from all these places.   My real Lucene doc has four fields, the forth being another database key that I can use to link to the specific comment or email where the search hit is.   BugTracker.NET supports custom text fields and in the future I hope to harvest that text from the database and add it to the Lucene doc.

So, if your app is like mine, with text in many different places, then you’ll have a challenge like mine, how to package the text into a Lucene doc.

static Lucene.Net.Documents.Document create_doc(int bug_id, string text)
{
Lucene.Net.Documents.Document doc = new Lucene.Net.Documents.Document();

doc.Add(new Lucene.Net.Documents.Field(
“text”,
new System.IO.StringReader(text)));

doc.Add(new Lucene.Net.Documents.Field(
“bug_id”,
Convert.ToString(bug_id),
Lucene.Net.Documents.Field.Store.YES,
Lucene.Net.Documents.Field.Index.UN_TOKENIZED));

// For the highlighter, store the raw text
doc.Add(new Lucene.Net.Documents.Field(
“raw_text”,
text,
Lucene.Net.Documents.Field.Store.YES,
Lucene.Net.Documents.Field.Index.UN_TOKENIZED));

return doc;
}

3) Updating the index

Whenever a user updates text in a bug I launch a worker thread to update the index.    The worker thread grabs a lock so that only one thread is updating the index at a time.

The worker thread creates a Lucene “IndexModifier”, deletes the old doc, and replaces it with a new one.

Notice that the thread closes the “searcher”.   The searcher is a Lucene “Searcher”.   The life cycle of a Searcher is that it first loads the index and then does its searches using that loaded, cached version of the index.   If the real index changes on disk, the searcher wouldn’t know about it.   It would continue searching the out-of-date cached copy of the index in its memory.    That might be ok for your situation, and if your index is very big and the cost of creating a new searcher is high, you might be forced to use a searcher with a stale index.   BugTracker.NET databases tend to be small, so I can get away with making sure my searcher always has an up-to-date index to work with.

The official Lucene fact says that a Searcher (aka IndexSearcher) “is thread-safe. Multiple search threads may use the same instance of IndexSearcher concurrently without any problems. It is recommended to use only one IndexSearcher from all threads in order to save memory.”

Lucene.Net.Search.Searcher searcher = null;

static void threadproc_update(object obj)
{
lock (my_lock) // If a thread is updating the index, no other thread should be doing anything with it.
{

try
{
if (searcher != null)
{
try
{
searcher.Close();
}
catch (Exception e)
{
btnet.Util.write_to_log(“Exception closing lucene searcher:” + e.Message);
}
searcher = null;
}

Lucene.Net.Index.IndexModifier modifier = new Lucene.Net.Index.IndexModifier(“c:\\folder_where_lucene_index_lives”, analyzer, false);

// same as build, but uses ”modifier” instead of write.
// uses additional ”where” clause for bugid

int bug_id = (int)obj;

modifier.DeleteDocuments(new Lucene.Net.Index.Term(“bug_id”, Convert.ToString(bug_id)));

DataSet ds = btnet.DbUtil.get_dataset(“select bug_id, bug_text from bugs where bug_id = ” + ConvertToString(bug_id));

foreach (DataRow dr in ds.Tables[0].Rows) // one row…
{
modifier.AddDocument(create_doc(
(int)dr["bug_id"],
(string)dr["bug_text"]));
}

modifier.Flush();
modifier.Close();

}
catch (Exception e)
{
btnet.Util.write_to_log(“exception updating Lucene index: ” + e.Message);
}
}
}

4) Sending the search query to Lucene

To search, create a Lucene “QueryParser”.    Call its Parse() method passing the text the user typed in.   The Parse() method returns a “Query”.   Call the Searcher’s Search() method passing the Query.   The Search() method returns a Lucene “Hits” object, a collection of the search hits.

As I’ve mentioned, I want my searcher to always be using the most up-to-date index, so whenever I do update the index, I destroy the old searcher, and then recreate it again the next time it’s needed.

Since IIS is handling the HTTP requests with multiple threads, these searches are happening on multiple threads.   Each search tries to grab my one-and-only lock, the one that keeps the updating threads from conflicting with each other and that keeps the updating threads from conflicting with searches.     Because there is just this one-and-only lock, all the searches on the website have to line up in single-file to get through this bottleneck.   Sounds terrible, doesn’t it?   But so far, no reports of any problems.   It’s just a bug tracker, not twitter, and so I can get away with this design, and there’s no confusion ever about people doing searches with out-of-date indexes.

Lucene.Net.QueryParsers.QueryParser parser = new Lucene.Net.QueryParsers.QueryParser(“text”, analyzer );
Lucene.Net.Search.Query query = null;

try
{
if (string.IsNullOrEmpty(text_user_entered))
{
throw new Exception(“You forgot to enter something to search for…”);
}

query = parser.Parse(text_user_entered);

}
catch (Exception e)
{
display_exception(e);
}

lock (my_lock)
{

Lucene.Net.Search.Hits hits = null;
try
{
if (searcher == null)
{
searcher = new Lucene.Net.Search.IndexSearcher(“c:\\folder_where_lucene_index_lives”);
}

hits = searcher.Search(query);

}
catch (Exception e)
{
display_exception(e);
}

for (int i = 0; i &lt; hits.Length(); i++)
{
Lucene.Net.Documents.Document doc = hits.Doc(i);
~~
~~ more processing of the hits and the Lucene docs here ~~
~~
}
}

5) Displaying the results

If you didn’t like my design prior to this point, what with the locking and the bottleneck, then you are going to really hate it now, because it gets weird now.    The search results I get back from Lucene is in the form of a Hits object, a collection of hits that you access by index.   The collection is in the order of the probability score, which you can get using the Hits.Score() method.   You can also get at the Lucene Document related to the hit via the Hits.Doc() method.

Now, back when I was designing my Lucene Document, I had to be thinking ahead regarding how I would display the results.   Would I display the results based purely on what’s in the document?   If so, then I would have had to add fields to the doc for everything I wanted to eventually be displaying, not just the fields I needed for search.   The more fields I put in the doc, the more I would have to be updating the doc and the index to keep it in sync with my database, and the more I would be duplicating database data in the Lucene index.   So, there was a downside to relying strickly on the Lucene doc for my display.

Also, and for me more importantly, I already have a page in my app that knows how to display a list of bugs based on the result of a SQL query.   I didn’t want to have to adopt that page to work with a Lucene Hits object.    I wanted to somehow convert the Lucene results into the format expected by that existing page.

So, I decided to try importing the Hits into the database, then letting my existing page fetch the hits out of the database, joining the hits to my bugs table to pick up the fields that I had not bothered to duplicate in the Lucene doc as fields.

The code below shows how I imported the Lucene hits into the database.    In short, I create a big batch of SQL Statements and execute them in one trip to the server.    The batch of SQL Statements creates a temporary table with a unique name plus a bunch of insert statements, one for every Lucene hit I want to import and display.    I import the best 100 hits, which is more than enough.   Lucene can find multiple hits in the same document, but I only want to list a given bug once in the search results, so I have logic for that below, the dict_already_seen_ids.

You will probably want to show your users the text around where the hit is, with the searched-for words highlighted, displayed in their context.   Lucene can prepare that displayable snippet of text for your.   You have to create a bunch of Lucene objects, a Formatter, a SimplerFragmenter, a QueryScorer, a Highlighter, etc, as does my code below.   I specified a snippet length of 400 characters and I specified the highlighting to be done using this HTML:  <span style=’background:yellow;’></span>.    I feed to the highlighter the original Query and the raw text that I had saved in the doc.   Lucene then gave me the formatted, highlighted snippets, which I inserted into my temporary database table.

You might think that the import of the Lucene hits into the database would perform poorly, but actually, it’s fast.    Had this not worked, then my plan B would have been to create a more complete Lucene Doc, and then somehow programmatically synthesize an ADO.NET recordset for my page downstream that displays results.

Lucene.Net.Highlight.Formatter formatter = new Lucene.Net.Highlight.SimpleHTMLFormatter(
“<span style=’background:yellow;’>”,
“</span>”);

Lucene.Net.Highlight.SimpleFragmenter fragmenter = new Lucene.Net.Highlight.SimpleFragmenter(400);
Lucene.Net.Highlight.QueryScorer scorer = new Lucene.Net.Highlight.QueryScorer(query);
Lucene.Net.Highlight.Highlighter highlighter = new Lucene.Net.Highlight.Highlighter(formatter, scorer);
highlighter.SetTextFragmenter(fragmenter);

StringBuilder sb = new StringBuilder();
string guid = Guid.NewGuid().ToString().Replace(“-”, ”");
Dictionary&lt;string, int&gt; dict_already_seen_ids = new Dictionary&lt;string, int&gt;();
sb.Append(@”
create table #$GUID
(
temp_bg_id int,
temp_score float,
temp_text nvarchar(3000)
)
“);

// insert the search results into a temp table which we will join with what’s in the database
for (int i = 0; i < hits.Length(); i++)
{
if (dict_already_seen_ids.Count < 100)
{
Lucene.Net.Documents.Document doc = hits.Doc(i);
string bg_id = doc.Get(“bg_id”);
if (!dict_already_seen_ids.ContainsKey(bg_id))
{
dict_already_seen_ids[bg_id] = 1;
sb.Append(“insert into #”);
sb.Append(guid);
sb.Append(“ values(“);
sb.Append(bg_id);
sb.Append(“,”);
//sb.Append(Convert.ToString((hits.Score(i))));
sb.Append(Convert.ToString((hits.Score(i))).Replace(“,”, ”.”));  // Somebody said this fixes a bug. Localization issue?
sb.Append(“,N’”);

string raw_text = Server.HtmlEncode(doc.Get(“raw_text”));

Lucene.Net.Analysis.TokenStream stream = analyzer.TokenStream(“”, new System.IO.StringReader(raw_text));
string highlighted_text = highlighter.GetBestFragments(stream, raw_text, 1, ”…”).Replace(“‘”, ”””);

if (highlighted_text == ”") // someties the highlighter fails to emit text…
{
highlighted_text = raw_text.Replace(“‘”,”””);
}
if (highlighted_text.Length > 3000)
{
highlighted_text = highlighted_text.Substring(0,3000);
}
sb.Append(highlighted_text);
sb.Append(“‘”);
sb.Append(“)\n”);
}
}
else
{
break;
}
}

We’re done.  I’d be very interested in your feedback.   Was my explanation here helpful to you?   Were my design choices stupid?   I’d like to hear from you.

http://www.ifdefined.com/blog/post/2009/02/Full-Text-Search-in-ASPNET-using-LuceneNET.aspx

Loading XML Documents
Loading of an XML document is accomplished by calling the Load() method, which reads XML data
and populates the document tree structure. There are four different versions of the Load() method, each
of which uses a different source to read the data. Here are the various forms of the Load() method:
❑ Load(Stream): Loads the document from a Stream data source
❑ Load(string): Loads the document using the given file name string
❑ Load(TextReader): Loads the document using a TextReader as the data source
❑ Load(XmlReader): Loads the document using the given XmlReader as the data source
In addition to taking a Stream, TextReader, and XmlReader objects, the Load() method also takes in a
file name as a string argument. Using this method, you can load an XML document from the specified
URL. Apart from the overloaded Load() methods, there is also a method named LoadXml() that makes
it possible to load the XML document from a string of data as its argument.

Cơ bản về XML và DOM

Exploring DOM Processing

The DOM is a specification for an API that lets programmers manipulates XML held in memory. The
DOM specification is language-independent, and bindings are available for many programming lan-
guages, including C++. XmlDocument is based upon the DOM, with Microsoft extensions. Because it
works with XML in memory, it has several advantages and disadvantages over the XmlReader forward-
only approach.
One advantage is that, in reading the entire document and building a tree in memory, you have access to all
the elements and can wander through the document at will. You can also edit the document, changing,
adding, or deleting nodes, and write the changed document back to disk again. It is even possible to create
an entire XML document from scratch in memory and write it out—serialize it—and this is a useful alter-
native to using XmlWriter.
The main disadvantage is that the whole of an XML document is held in memory at once, so the amount
of memory needed by your program is going to be proportional to the size of the XML document you’re
working with. This means that if you’re working with a very large XML document—or have limited
memory—you might not be able to use XmlDocument. Another disadvantage is that the API for the
XmlDocument is specified through the DOM model, limiting the options for implementing performance
improvements behind the XmlDocument class.


XML Document Loaded in a DOM Tree
Working with an XmlDocument class is fundamentally different from working with the XmlReader and
XmlWriter classes, although they share some similarities, such as the concept of nodes. When you use
DOM processing, the entire XML document is loaded into a tree structure that matches the hierarchical
structure of the document. The DOM provides a set of functions that examine the tree structure and
manipulate the document’s content. To see an example of this, consider the XML document shown in
Listing 6-1 that contains a simple book store along with information about the various books that are
part of the bookstore.
Listing 6-1: XML Document That Represents the Bookstore

<?xml version=’1.0’?>
<!– This file represents a fragment of a book store inventory database –>
<bookstore>
<book genre=”autobiography”>
<title>The Autobiography of Benjamin Franklin</title>
<author>
<first-name>Benjamin</first-name>
<last-name>Franklin</last-name>

</author>

<price>8.99</price>
</book>
<book genre=”novel”>
<title>The Confidence Man</title>
<author>
<first-name>Herman</first-name>
<last-name>Melville</last-name>
</author>
<price>11.99</price>
</book>
<book genre=”philosophy”>
<title>The Gorgias</title>
<author>
<name>Plato</name>
</author>
<price>9.99</price>
</book>
</bookstore>

Note that the books.xml file shown in Listing 6-1 is used throughout all the examples presented in this
chapter. An XML document has a tree structure under the DOM, and each object in the tree is a node. T
document, modeled using the DOM, would be represented as the tree structure shown in Figure 6-1.

domtree

domtree

Tóm lượt từ các tutorial tại www.asp.net

Create User:

link gốc : http://www.asp.net/learn/security/tutorial-05-cs.aspx

MembershipCreateStatus createStatus;

MembershipUser newUser = Membership.CreateUser(Username.Text, Password.Text, Email.Text, passwordQuestion, SecurityAnswer.Text, true, out createStatus);

kiểm tra quá trình create user bằng creatStatus.

Kiểm tra quyền của user:

link : http://www.asp.net/learn/security/tutorial-08-cs.aspx

Get a reference to the currently logged on user

MembershipUser currentUser = Membership.GetUser();

Determine the currently logged on user's UserId value

Guid currentUserId = (Guid)currentUser.ProviderUserKey;

Kiểm tra Role của user hiện tại:

bool allow = (currentUser.IsInRole("Role cần kiểm tra"))

Tạm thời copy 2 em thường dùng nhưng cũng thường quên nhất :(

RemoveHTML

using System.Text.RegularExpressions;

  ...

  public static string RemoveHTML(string in_HTML)
    {
      return Regex.Replace(in_HTML, "<(.|\n)*?>", "");
    }

Solution

Reference articles:

  • Tip/Trick: Url Rewriting with ASP.NET by Scott Guthrie – Examines four approaches: 1) Use Request.PathInfo Parameters Instead of QueryStrings; 2) Using an HttpModule to Perform URL Rewriting; 3) Using an HttpModule to Perform Extension-Less URL Rewriting with IIS7; 4) ISAPIRewrite to enable Extension-less URL Rewriting for IIS5 and IIS6; also discusses how to handle ASP.NET postbacks correctly with URL rewriting.
  • URL Rewriting by Salman (CSharpFriends) – simple implementation of URL rewriting logic within the Application_BeginRequest() method of the Global.asax file.
  • Rewrite.NET – A URL Rewriting Engine for .NET by Robert Chartier (15Seconds.com). Solution steps:
    • Create the HttpModule to process the web request and rewrite the URL
    • Add the handler in Web.config
    • Create a configuration section in Web.config to define URL mapping rules
    • Add extensibility by creating a rules engine interface
    • Write class or classes to implement rules engine interface
    • Add code to the HttpModule to dynamically load the desired rules from Web.config
  • URL Rewriting in ASP.NET by Scott Mitchell (MSDN) – examines how to implement URL rewriting in a HTTP module; also explains how to handle postbacks.
  • URL Rewriting with ASP.NET by Richard Birkby (CodeProject) – shows how legacy ASP sites can be upgraded to ASP.NET, while maintaining links from search engines. Solution steps:
    • Create the configuration section in Web.config for defining URL mapping rules
    • Write the configuration section handler class, incorporating the URL rewriting logic
    • Create a call to handler in Global.asax in Application_BeginRequest() method
    • Compile the code and install the rewriter assembly in the Global Assembly Cache (GAC)
    • Configure IIS to map non- .aspx files to the ASP.NET ISAPI extension

Related Resources

Follow

Get every new post delivered to your Inbox.