118 votos

¿Cómo puedo tener un mayor control en ASP.NET?

Estoy tratando de construir un muy, muy simple "micro-webapp", que sospecho que será de interés para un par de Stack Overflow'rs si alguna vez vuelvo a hacerlo. Que estoy recibiendo en mi C# en Profundidad sitio, que es de vainilla ASP.NET 3.5 (es decir. no MVC).

El flujo es muy simple:

  • Si un usuario entra en la aplicación con una URL que no especifica todos los parámetros (o si alguno de ellos no son válidos), sólo quiero mostrar los controles de entrada de usuario. (Sólo hay dos).
  • Si un usuario entra en la aplicación con una URL que no tienen todos los parámetros requeridos, quiero mostrar los resultados y los controles de entrada (por lo que puede cambiar los parámetros)

Aquí están mis auto-impuesta requisitos (mezcla de diseño e implementación):

  • Quiero que la sumisión a utilizar GET en lugar de POST, sobre todo por lo que los usuarios pueden marcar la página con facilidad.
  • Yo no quiero la URL a acabar pareciendo tonto después de la presentación, con extraños partes y piezas. Sólo la URL principal y el real parámetros, por favor.
  • Idealmente me gustaría evitar que requiere JavaScript. No hay ninguna razón para que en esta aplicación.
  • Quiero ser capaz de acceder a los controles durante el tiempo de procesamiento y el conjunto de valores, etc. En particular, quiero ser capaz de establecer los valores predeterminados de los controles a los valores de parámetro pasa, si ASP.NET no puede hacer esto automáticamente para mí (dentro de las restricciones).
  • Estoy feliz de hacer todos los parámetros de validación de mí mismo, y no necesito mucho en la forma de eventos del lado del servidor. Es realmente sencillo de configurar todo en la carga de la página en lugar de asociar eventos a los botones, etc.

La mayoría de esto está bien, pero no he encontrado ninguna manera de completamente eliminando el viewstate y manteniendo el resto de las funcionalidades útiles. El uso de los post de este blog me las he arreglado para evitar cualquier real valor para el viewstate - pero aún así termina como un parámetro en la URL, lo que se ve realmente feo.

Si me hacen un simple formulario HTML en lugar de un ASP.NET forma (es decir. saca runat="server"), a continuación, no tengo ninguna magia viewstate - pero entonces no puedo acceder a los controles mediante programación.

Yo podría hacer todo esto, haciendo caso omiso de la mayoría de ASP.NET y la creación de un documento XML con LINQ to XML, y la aplicación de IHttpHandler. Que se siente un poco de nivel bajo.

Me doy cuenta de que mi problema podría ser resuelto por cualquiera de las relajante mis limitaciones (p. ej. el uso de POST y no preocuparse sobre el excedente de parámetro) o mediante el uso de ASP.NET MVC, pero son mis requisitos muy razonable?

Tal vez ASP.NET simplemente no se escala hacia abajo a este tipo de aplicaciones? Existe una alternativa probable, sin embargo: sólo estoy siendo estúpida, y hay una muy sencilla forma de hacerlo que no he encontrado.

Cualquier pensamiento, cualquier persona? (Cue comentarios de cómo los poderosos han caído, etc. Que bien espero que nunca he dicho ser un ASP.NET experto, ya que la verdad es todo lo contrario...)

69voto

Dan Herbert Puntos 38336

Esta solución le dará el acceso mediante programación a los controles en su totalidad, incluyendo todos los atributos de los controles. Además, sólo los valores del cuadro de texto aparecerá en la URL en la presentación de modo a OBTENER la URL de la solicitud será más "significativas"

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="JonSkeetForm.aspx.cs" Inherits="JonSkeetForm" %>
<!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>Jon Skeet's Form Page</title>
</head>
<body>
    <form action="JonSkeetForm.aspx" method="get">
    <div>
        <input type="text" ID="text1" runat="server" />
        <input type="text" ID="text2" runat="server" />
        <button type="submit">Submit</button>
        <asp:Repeater ID="Repeater1" runat="server">
            <ItemTemplate>
                <div>Some text</div>
            </ItemTemplate>
        </asp:Repeater>
    </div>
    </form>
</body>
</html>

A continuación, en el código subyacente que puede hacer todo lo que usted necesita en PageLoad

public partial class JonSkeetForm : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        text1.Value = Request.QueryString[text1.ClientID];
        text2.Value = Request.QueryString[text2.ClientID];
    }
}

Si usted no desea un formulario que tiene runat="server", entonces usted debe utilizar los controles HTML. Es más fácil trabajar con ella para sus fines. Sólo uso regular las etiquetas HTML y poner runat="server" y darle un ID. A continuación, puede acceder a ellos mediante programación y código sin ViewState.

El único inconveniente es que usted no tendrá acceso a muchas de las "útil" ASP.NET controles de servidor como GridViews. He incluido una Repeater en mi ejemplo, porque estoy asumiendo que usted quiere tener los campos en la misma página de los resultados y (a mi conocimiento) Repeater es el único control enlazado a datos que se ejecute sin un runat="server" de atributo en la etiqueta Form.

12voto

Dylan Beattie Puntos 23222

Definitivamente eres (en mi humilde opinión) a la derecha de la pista, por no utilizar runat="server" en su etiqueta. Esto sólo significa que usted tendrá que extraer valores de la Request.QueryString directamente, aunque, como en este ejemplo:

En la página .aspx en sí:

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

<!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>
  <title>ASP.NET with GET requests and no viewstate</title>
</head>
<body>
    <asp:Panel ID="ResultsPanel" runat="server">
      <h1>Results:</h1>
      <asp:Literal ID="ResultLiteral" runat="server" />
      <hr />
    </asp:Panel>
    <h1>Parameters</h1>
    <form action="FormPage.aspx" method="get">
    <label for="parameter1TextBox">
      Parameter 1:</label>
    <input type="text" name="param1" id="param1TextBox" value='<asp:Literal id="Param1ValueLiteral" runat="server" />'/>
    <label for="parameter1TextBox">
      Parameter 2:</label>
    <input type="text" name="param2" id="param2TextBox"  value='<asp:Literal id="Param2ValueLiteral" runat="server" />'/>
    <input type="submit" name="verb" value="Submit" />
    </form>
</body>
</html>

y en el código subyacente:

using System;

public partial class FormPage : System.Web.UI.Page {

        private string param1;
        private string param2;

        protected void Page_Load(object sender, EventArgs e) {

            param1 = Request.QueryString["param1"];
            param2 = Request.QueryString["param2"];

            string result = GetResult(param1, param2);
            ResultsPanel.Visible = (!String.IsNullOrEmpty(result));

            Param1ValueLiteral.Text = Server.HtmlEncode(param1);
            Param2ValueLiteral.Text = Server.HtmlEncode(param2);
            ResultLiteral.Text = Server.HtmlEncode(result);
        }

        // Do something with parameters and return some result.
        private string GetResult(string param1, string param2) {
            if (String.IsNullOrEmpty(param1) && String.IsNullOrEmpty(param2)) return(String.Empty);
            return (String.Format("You supplied {0} and {1}", param1, param2));
        }
    }

El truco aquí es que estamos usando ASP.NET los Literales dentro del valor de="" los atributos del texto de las entradas, por lo que los cuadros de texto en sí no tiene que runat="server". Los resultados son luego se envuelve dentro de un ASP:Panel, y la propiedad Visible establecida en la página de la carga dependiendo de si desea mostrar todos los resultados o no.

2voto

user134706 Puntos 895

Bueno Jon, el viewstate cuestión primera:

No he comprobado si hay algún tipo de código interno cambiar desde el 2.0 pero he aquí cómo he manejado deshacerse de la viewstate hace un par de años. En realidad que oculta campo es codificado dentro de HtmlForm así que usted debe derivar su nuevo y de paso en su representación de hacer las llamadas por ti mismo. Tenga en cuenta que también puede dejar __eventtarget y __eventtarget si nos atenemos a plain old controles de entrada (que supongo que lo que quieres ya que también ayuda a que no requiere de JS en el cliente):

protected override void RenderChildren(System.Web.UI.HtmlTextWriter writer)
{
    System.Web.UI.Page page = this.Page;
    if (page != null)
    {
        onFormRender.Invoke(page, null);
        writer.Write("<div><input type=\"hidden\" name=\"__eventtarget\" id=\"__eventtarget\" value=\"\" /><input type=\"hidden\" name=\"__eventargument\" id=\"__eventargument\" value=\"\" /></div>");
    }

    ICollection controls = (this.Controls as ICollection);
    renderChildrenInternal.Invoke(this, new object[] {writer, controls});

    if (page != null)
        onFormPostRender.Invoke(page, null);
}

Para obtener esos 3 estática MethodInfo y hablar con ellos saltarse esa viewstate parte ;)

static MethodInfo onFormRender;
static MethodInfo renderChildrenInternal;
static MethodInfo onFormPostRender;

y he aquí su formulario, escriba el constructor:

static Form()
{
    Type aspNetPageType = typeof(System.Web.UI.Page);

    onFormRender = aspNetPageType.GetMethod("OnFormRender", BindingFlags.Instance | BindingFlags.NonPublic);
    renderChildrenInternal = typeof(System.Web.UI.Control).GetMethod("RenderChildrenInternal", BindingFlags.Instance | BindingFlags.NonPublic);
    onFormPostRender = aspNetPageType.GetMethod("OnFormPostRender", BindingFlags.Instance | BindingFlags.NonPublic);
}

Si yo estoy volviendo a su pregunta, usted también desea no utilizar POST como la acción de sus formas, así que aquí está cómo usted haría:

protected override void RenderAttributes(System.Web.UI.HtmlTextWriter writer)
{
    writer.WriteAttribute("method", "get");
    base.Attributes.Remove("method");

    // the rest of it...
}

Supongo que esto es bastante. Déjame saber cómo va.

EDIT: me olvidé de la Página viewstate métodos:

Para que su Formulario personalizado : HtmlForm presenta su nuevo resumen (o no) Página : System.Web.UI.Page :P

protected override sealed object SaveViewState()
{
    return null;
}

protected override sealed void SavePageStateToPersistenceMedium(object state)
{
}

protected override sealed void LoadViewState(object savedState)
{
}

protected override sealed object LoadPageStateFromPersistenceMedium()
{
    return null;
}

En este caso, el sello de los métodos porque no se puede sellar la Página (incluso si no es abstracto Scott Guthrie se envuelven en otra :P), pero usted puede sellar su Forma.

1voto

tvanfosson Puntos 268301

¿Ha pensado en no eliminar el POST sino redirigir a una URL GET adecuado cuando se publique el formulario. Es decir, que aceptan tanto GET y POST, pero en la POST construir una petición GET y redirigir a la misma. Esto podría ser manejado ya sea en la página oa través de un HttpModule si quería hacerla página independiente. Creo que esto sería hacer las cosas mucho más fáciles.

EDIT: se supone que tiene EnableViewState = "false" ubicado en la página.

1voto

Mehrdad Afshari Puntos 204872

Me gustaría crear un módulo HTTP que se encarga del enrutamiento (similar a la de la MVC, pero no sofisticados, sólo un par if de las declaraciones) y de la mano a aspx o ashx páginas. aspx es preferible porque es más fácil modificar la plantilla de página. Yo no usaría WebControls de la aspx sin embargo. Solo Response.Write.

Por el camino, para simplificar las cosas, usted puede hacer la validación de parámetros en el módulo (ya que comparte código con enrutamiento probablemente) y guardarlo en HttpContext.Items y, a continuación, convertirlos en la página. Esto funciona más o menos como el MVC sin todos de la campana y silbatos. Esto es lo que yo hice mucho antes de ASP.NET MVC días.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by: