Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Real - World ASP .NET—Building a Content Management System - StephenR. G. Fraser

.pdf
Скачиваний:
67
Добавлен:
24.05.2014
Размер:
4.59 Mб
Скачать

private void BuildImageButton(TableRow row, string cArg)

{

ImageButton ibn = new ImageButton();

if (cArg != null)

{

ibn.Command += new CommandEventHandler(this.btn_Click);

ibn.ImageUrl = "Images/btnSelect.gif";

ibn.CommandArgument = cArg;

}

else

ibn.ImageUrl = "Images/blank.gif";

TableCell cell = new TableCell();

cell.Controls.Add(ibn);

cell.HorizontalAlign = HorizontalAlign.Center;

cell.VerticalAlign = VerticalAlign.Middle;

row.Cells.Add(cell);

}

To create a Command with a CommandArgument, simply assign a CommandEventHandler, of the method you want to execute, to the image button's Command property. Then assign a string argument to the CommandArgument property.

When the user eventually clicks any of the Image buttons, the btn_Click() command is triggered. As you can see in Listing 11-7, all you need to do is get the CommandArgument you stuffed in earlier from the CommandEventArgs parameter passed by the method.

Listing 11-7: The AutList.cs btn_Click Code

private void btn_Click(object sender, CommandEventArgs e)

{

Response.Redirect(e.CommandArgument.ToString());

}

Creating New Content

You can list all the content in the system. It's kind of boring, however, if you don't have any way of getting content into the CMS. Let's fix that.

The AutCreate Web Page

Figure 11-7 shows CMS.NET's simple content-creation Web page. The CMS you plan to develop will probably be a little more detailed, but this is what is needed for this CMS.NET system.

Figure 11-7: The AutCreate Web page

Creating AutCreate.aspx is pretty straightforward. As you can see in Listing 11-8, the form is simply four text boxes, RequiredFieldValidator on the headline and body, a button to create the content, and another button to reset the form back to empty.

Listing 11-8: The AutCreate Web Form

<FORM id=AutCreate method=post runat="server">

<H2>

<FONT color=darkslategray>Author : Content Create</FONT>

</H2>

<P>

<asp:ValidationSummary id=ValidationSummary1 runat="server"

HeaderText="Error(s) occurred while creating content">

</asp:ValidationSummary >

<TABLE cellSpacing=1 cellPadding=3 width="95%"border=1>

<TR>

<TD style="WIDTH: 16%"><STRONG>Headline:</STRONG></TD>

<TD style="WIDTH: 80%">

<asp:TextBox id=tbHeadline runat="server" Width="100%"

TextMode="MultiLine">

</asp:TextBox> </TD>

<TD>  

<asp:RequiredFieldValidator id=RequiredFieldValidator1 runat="server" ErrorMessage="A Headline must be entered." Display="Dynamic"

ControlToValidate="tbHeadline" EnableClientScript="False" >*

</asp:RequiredFieldValidator>

</TD>

</TR > <TR>

<TD style="WIDTH: 16%"><STRONG>Teaser:</STRONG></TD > <TD style="WIDTH: 80%">

<asp:TextBox id=tbTeaser runat="server" Width="100%" TextMode="MultiLine" Rows="4">

</asp:TextBox>

</TD>

<TD> </TD>

</TR > <TR>

<TD style="WIDTH: 16%"><STRONG>Body:</STRONG></TD > <TD style="WIDTH: 80%">

<asp:TextBox id=tbBody runat="server" Width="100%" TextMode="MultiLine" Rows="16" >

</asp:TextBox> </TD>

<TD>  

<asp:RequiredFieldValidator id=RequiredFieldValidator2 runat="server" ErrorMessage="A body must be entered." Display="Dynamic"

ControlToValidate="tbBody" EnableClientScript="False">*

</asp:RequiredFieldValidator>

</TD>

</TR > <TR>

<TD style="WIDTH: 16%"><STRONG>Tagline:</STRONG></TD> <TD style="WIDTH: 80%">

<asp:TextBox id=tbTagline runat="server" Width="100%" TextMode="MultiLine">

</asp:TextBox>

</TD>

<TD> </TD>

</TR >

</TABLE>

</P>

<asp:Button id=bnNext runat="server" Text="Create Content">

</asp:Button>

 

<INPUT type=reset value=Reset>

</FORM>

A simple little trick I found while designing this Web form is that you can use the plain old HTML Reset button to blank out the page. This will save you from having to do any coding in the Codebehind, which would be required if you were to use the intrinsic button control.

The AutCreate Codebehind

The code to handle the creation of a piece of content is beyond easy (see Listing 11-9). Get a Content table helper class. (Remember the helper classes from Chapter 10?) Then, insert the content you gathered using the helper class' Insert() method. Finally, go back to the content list Web page.

Listing 11-9: The AutCreate Page_Load Method

private void Page_Load(object sender, System.EventArgs e)

{

if (IsPostBack)

{

Page.Validate();

if (Page.IsValid)

{

Content content = new Content(new AppEnv(Context).GetConnection());

content.Insert(tbHeadline.Text, 1, tbTeaser.Text,

tbBody.Text, tbTagline.Text);

Response.Redirect("AutList.aspx");

}

}

}

 

 

Note

The

 

bylin

 

e is

 

hard-

 

code

 

d to

 

"1"

 

beca

 

use

 

at

 

this

 

point

 

there

 

is

 

only

 

one

 

user:

 

the

 

admi

 

nistra

 

tor.

 

This

 

code

 

will

 

be

 

upda

 

ted

 

later

 

to

 

use

 

the

 

curre

 

nt

 

logge

 

d-in

 

Acco

unt ID.

It is true that the Content.cs helper class method Insert() (see Listing 11-10) is a little more complex, but you have already seen this almost exact code twice before in the

Account and AccountProperty table helper classes.

Listing 11-10: The Content Database Helper Insert and NextContentID Methods

public void Insert(string Headline, int Byline, string Teaser, string Body, string Tagline)

{

Insert(NextContentID(), 1, Headline, Byline, Teaser, Body,

Tagline, Byline);

}

public void Insert(int ContentID, int Version, string Headline, int Byline, string Teaser, string Body, string Tagline, int UpdUserID)

{

// INSERT INTO Content (ContentID, Version, Headline, Byline,

//

Teaser, Body, Tagline, Status, UpdateUserID,

 

 

//

ModifiedDate, CreationDate)

 

//VALUES (@ContentID, @Version, @Headline, @Byline, @Teaser, @Body,

//@Tagline, @Status, @UpdateUserID, @ModifiedDate, @CreationDate)

SqlCommand Command = new SqlCommand("Content_Insert", m_Connection); Command.CommandType = CommandType.StoredProcedure;

Command.Parameters.Add(new SqlParameter("@ContentID", SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@Version", SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@Headline", SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Byline", SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@Teaser", SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Body", SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Tagline", SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Status", SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@UpdateUserID", SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@ModifiedDate",

SqlDbType.DateTime));

Command.Parameters.Add(new SqlParameter("@CreationDate",

SqlDbType.DateTime));

Command.Parameters["@ContentID"].Value

= ContentID;

 

 

 

Command.Parameters["@Version"].Value

= Version;

 

 

 

 

Command.Parameters["@Headline"].Value

= Headline;

 

Command.Parameters["@Byline"].Value

= Byline;

 

 

 

 

 

Command.Parameters["@Teaser"].Value

= Teaser;

 

 

 

Command.Parameters["@Body"].Value

= Body;

 

 

 

Command.Parameters["@Tagline"].Value

= Tagline;

 

 

 

Command.Parameters["@Status"].Value

= StatusCodes.Creating;

Command.Parameters["@UpdateUserID"].Value = UpdUserID;

Command.Parameters["@ModifiedDate"].Value = DateTime.Now;

Command.Parameters["@CreationDate"].Value = DateTime.Now;

try

{

m_Connection.Open();

Command.ExecuteNonQuery();

}

finally

{

m_Connection.Close();

}

}

public int NextContentID()

{

//SELECT DISTINCT ContentID

//FROM Content

//ORDER BY ContentID DESC

SqlCommand Command = new SqlCommand("Content_NextContentID", m_Connection);

Command.CommandType = CommandType.StoredProcedure;

SqlDataAdapter DAdpt = new SqlDataAdapter(Command);

DataSet ds = new DataSet();

DAdpt.Fill(ds, "Content");

if (ds.Tables["Content"].Rows.Count <= 0) return 1;

return Convert.ToInt32(ds.Tables["Content"].Rows[0]["ContentID"]) + 1;

}

To simplify the call made to the Insert() method in AutCreate.cs, I created an overloaded version of it. You should already know that overloaded methods are two or more methods within a class that use the same name but different parameters. Usually each method has very similar functionality, but this is not a requirement.

The overloaded method includes the NextContentID() method (see Listing 11-10), which determines the next ContentID. It also hard-codes the version number to "1" because it is always the first version. You also know that the user to last touch the content is the same person who is creating it, so you can set that parameter to the same as the Byline.

Error Handling

Okay, what happens if you get an unexpected database error during the insertion of the

content? I bet you've seen Figure 11-8—the error page of shame. Is there a better page you can show the user or at least a page that is less embarrassing? Thank goodness, there is. In fact, there are several options.

Figure 11-8: .NET's error page of shame

The easiest way to replace the .NET error page is to replace it with a generic one of your own. It's very simple to do this. You just make the following change to the root directory version of your web.config file:

<configuration>

<system.web>

...

<customErrors defaultRedirect="http://localhost/CMSNET/ErrorPage.aspx"

mode="On"/>

...

</system.web>

</configuration>

Obviously, the location of the ErrorPage.aspx can be anywhere you want and, of course, you have to create the ErrorPage.aspx.

If you want a user to see your generic message, on the other hand, but you also want the developers on the local host to see the more informative error message, you simply change the mode to remoteOnly.

The <customErrors> element has one more trick up its sleeve. It is possible to redirect error messages based on the status code of the Web page error, as shown here:

<customErrors defaultRedirect="http://localhost/CMSNET/ErrorPage.aspx

mode="remoteOnly">

<error statuscode="403" redirect="NoAccess.aspx" />

<error statuscode="404" redirect="NotFound.aspx" />

</customErrors>

As long as you have set the mode to on or redirect, it is also possible to redirect the error page based specifically on the Web page where the error occurred. This is done in the @page directive at the top of each ASPX file, as shown here:

< @page ... ErrorPage="thispages_errorpage.aspx" />

Note that only one @page directive is allowed per Web page; therefore, you must tack it onto the end of the autogenerated one.

Each of the prec eding handles errors generically. If the Web page errors out, this error page will intercept the error before the .NET error page appears. But what if you know that an error happens periodically and you want to capture it in a more exacting fashion? Of course, this is a job for the exception handler. All you have to do is catch the exception yourself and process or redirect the error as you see fit. Listing 11-11 shows AutCreate's Page_Load() method using exception handling. As you can see, when an error occurs, the Web page redirects the user to another custom error page. This time, you can pass almost any information you like to the error page. Here, I'm passing the exception error message.

Listing 11-11: The Revised AutCreate's Page_Load Method

private void Page_Load(object sender, System.EventArgs e)

{

if (IsPostBack)

{

if (Page.IsValid)

{

try

{

Content content =

new Content(new AppEnv(Context).GetConnection());

content.Insert(tbHeadline.Text, 1, tbTeaser.Text,

tbBody.Text, tbTagline.Text);

}

catch (Exception err)

{

Response.Redirect("Error.aspx?ErrMsg=" +

HttpUtility.UrlEncode("The following error occurred: " +

err.Message));

}

Response.Redirect("AutList.aspx");

}

}

}

Wait a second, what is this HttpUtility.UrlEncode() method? As you probably know, certain characters should not appear in an http address, most notably the space character. To overcome this, .NET provides a method that encodes the URL so that it is valid for redirecting. There is also a HttpUtility.UrlDecode() method, but I am sure you figured that out already.

Warning The Response.Redirect() method throws a ThreadAbortException. This is because the execution is terminating the current page thread. Because this occurs, you need to place the redirect() method outside of the try block.

Соседние файлы в предмете Программирование