Problema con declaraciones estáticas

Iniciado por WHK, 11 Julio 2013, 20:15 PM

0 Miembros y 1 Visitante están viendo este tema.

WHK

Hola, estoy desarrollando un sistema en ASP bajo c# con .net 4.5 y tengo un problema:

Necesito acceder de una clase a otra ya que tengo una clase principal y desde ahi hago todas las inclusiones de los controles de usuario hacia un mismo form dinamicamente pero cada uno tiene funcionalidades distintas y no puedo unir todos las funciones de todas las clases en una sola.

Asi que lo que hice fue crear multiples clases con valores y funciones, por ejemplo una de ellas es la encargada de manejar las configuraciones del sistema y para poder utilizarla desde todo el resto de las clases tube que declararla como estática.

El problema es que al ser estática esta persiste y todos los cambios realizados se mantienen cuando otra persona vuelve a visitar la página y es un gran problema. Esto me sucede con varias clases.

Para evitar esto intenté buscar la manera de intercomunicar clases una a otra sin utilizar static pero fue imposible.

Una solución fue crear una estructura al comienzo de la clase principal con todas las demas clases estaticas, entonces cuando se llama al evento Page_Unload seteo todas las variables a null, el problema es que debo hacerla una por una.

Igual estuve buscando información sobre como resetear una estructura, el problema sigue siendo que es static.

Cual sería la manera correcta para solucionar este tipo de problemas? Necesito hacer que exista una comunicación entre controles de usuario y por el momento estoy utilizando un namespace "This.Default" para llamar a todas las demás clases de forma recursiva pero estoy llegando al límite y no encuentro como solucionarlo.

Alguna idea?

Default.aspx.cs
Código (csharp) [Seleccionar]
using librerias.sql;

namespace This
{
    public partial class Default : System.Web.UI.Page
    {
public static cls_sql sql;

protected void Page_Load(object sender, EventArgs e)
{
sql = new cls_sql();

Control modulo = LoadControl(@"C:\...\modulo.ascx");
controlPrincipal.Controls.Add(modulo);
}
}
}


Ahora desde modulo.aspx.cs necesito acceder a sql por lo tanto lo hago así: This.Default.sql pero siendo estático hay ciertos valores que no quiero que se compartan entre otros usuarios y no quiero tener que controlar los permisos de usuario o del visitante cada ves que escribo una linea, por eso por el momento en Page_Unload los seteo todos a null.

Igual se que cuando carga la pagina se establece una nueva instancia del objeto pero quiero evitar que estos datos muertos sigan con vida despues de la ejecucion de la pagina.

Si tengo 500 proyectos corriendo en el mismo servidor no quiero tener 500 espacios de memoria ram ocupados sin que nadie tenga una sola visita, necesito que se eliminen cuando finalicen y no que queden vivos hasta que alguien mas ingrese.

Será error de diseño de ASP.NET? no lo se y lo quiero averiguar.

Novlucker

#1
¿Si digo que no termino de entender que es lo que intentas hacer? Si lo termino de entender probablemente pueda ayudarte :xD

¿Por qué estas declarando clases estáticas para compartir la información?

¿Como es que persisten ciertos datos?

Me parece más bien un problema de como tienes armada la solución, de arquitectura

Saludos
Contribuye con la limpieza del foro, reporta los "casos perdidos" a un MOD XD

"Hay dos cosas infinitas: el Universo y la estupidez  humana. Y de la primera no estoy muy seguro."
Albert Einstein

El Benjo

Yo diría que compartieras esa información mediante propiedades.
www.es.neftis-ai.com

Sí hay un mejor lenguaje de programación y es ese con el que puedes desarrollar tus objetivos.

WHK

Tengo una clase encargada de configurar todo, obtener los datos del web.config, establecer rutas, obtener rutas virtuales, obtener el modulo seleccionado etc etc.

Tengo la clase principal que es el Default.aspx.cs y desde ahi llamo al archivo de configuraciones... ahora, dinamicamente necesito cargar un modulo o sección asi que uso controles de usuario, cada módulo es un control de usuario, ahora desde este control de usuario necesito acceder a la clase de configuraciones para obtener las rutas y esas cosas.

No me sirve declarar la clase de configuraciones en la clase principal, en la clase del theme y en la del módulo porque tendré 3 declaraciones para una misma clase y si el módulo modifica un valor esta no se reflejará en el theme, por eso tube que hacer estática la clase de configuraciones para poder utilizarla desde todos los controles de usuario (theme y modulo) pero el problema es que cuando finaliza de cargar la web esos cambios y datos quedan guardados en la memoria ram del servidor esperando a ser reutilizados nuevamente.

Vamos, esto no es php, es asp compilado, la dll se ejecuta una sola ves y de ahi cada ves que se visita la pagina se llama a la funcion Page_Load pero la ejecución es la misma, no son threads ni forks por lo tanto las variables estaticas permanecen vivas.

Que tal si estoy modificando algo y justo al mismo tiempo entra otra persona y modifica la misma variable? se sobreescribirán y tendria que hacer un bloqueo sincronizado para las visitas y eso sería horrendo porque tendría que restringir a una llamada simultanea máxima cuando en php puedes hacer 500 si quieres al mismo tiempo y las clases y variables no se comparten en memoria a menos que uses sesiones, esto ahorra una inmensidad de memoria ram pero asp no lo hace y arrastra una carga de memoria hasta el infinito cuando tienes muchos sistemas en un mismo servidor, ese es mi problema.

WHK

Cita de: El Benjo en 11 Julio 2013, 20:37 PM
Yo diría que compartieras esa información mediante propiedades.

Y como sería eso mr elo? recuerda que esas clases contienen variables y funciones, no puedo compartir todas las variables en una sola clase o propiedad porque son clases distintas.

Como puedo hacer eso que dices?

Novlucker

Entendido :P

Para empezar, no es una buena práctica utilizar variables estáticas en ASP.NET, no para compartir información cuando tienes ViewState, Session e incluso Application.

Como te ha dicho El Benjo, la información entre controles se comparte mediante propiedades, que no son más que getters y setters para asignar y obtener los valores de esos controles.

Ej:
Código (csharp) [Seleccionar]
    public partial class MiControl : System.Web.UI.UserControl
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            TextBox1.Text = this.Nombre;
        }

        public string Nombre
        {
            get { return ViewState["_Nombre"] != null ? ViewState["_Nombre"].ToString() : string.Empty; }
            set { ViewState["_Nombre"] = value; }
        }
    }


Código (csharp) [Seleccionar]
public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        MiControl1.Nombre = "Novlucker";
    }
}


En mi ejemplo, MiControl utiliza ViewState para almacenar la información de sus propiedades, aunque no sea necesario guardarla ya que se la estoy cargando en cada Load de Default, pero por si no fuera así.

Saludos
Contribuye con la limpieza del foro, reporta los "casos perdidos" a un MOD XD

"Hay dos cosas infinitas: el Universo y la estupidez  humana. Y de la primera no estoy muy seguro."
Albert Einstein

El Benjo

#6
Mr Elo, jajajajajajaaja Da gusto que alguien conozca a la Electric Light Orchestra ;D

Bueno, deja ver si te entendí:

Tienes tu clase principal --> Default.aspx. Que se encarga de cargar otros módulos y estos módulos necesitan acceder a la clase "Configuraciones" (disculpa el nombre pero no lo especificas en el post), pero no quieres hacer la declaración en cada uno de ellos, ¿cierto?

Bueno, a como yo lo veo lo que necesitas es hacer la declaración de la clase de configuración únicamente en la clase Default.aspx.La clase Default.aspx seguirá creando los controles, pero a estos puedes hacerles la siguiente modoficación:

Vas a agregar un evento que será el evento cuando requieran un valor específico de una propiedad, y agregarás el manejador de dicho evento en la clase que crea al objeto, es decir en Default.aspx y esta comprobará el valor en la clase configuraciones.
Después Default.aspx cambiará el valor en el objeto que le hizo la petición (que levantó el evento), ya sea mediante una propiedad o llamando a un método.

Espero haberme dado a entender y que te sirva de algo.
www.es.neftis-ai.com

Sí hay un mejor lenguaje de programación y es ese con el que puedes desarrollar tus objetivos.

WHK

Vamos uno por uno...

He intentado probar lo de El Benjo  usando una función que retorna todo :p

public static object obtenerDatos()
{
return This.Default;
}


Pero me dice que es un tipo que no es válido en ese contexto asi que no me sirve a menos que encierre todas las variables en una estructura y pase solamente esa estructura, en ese caso podría declarar en cada cabecera de cada clase la obtencion de dichas clases pero al ser un contexto distinto no se si se establecerán clonadas en ves de pasarse recursivamente.

En este caso tendría que hacer una función o un argumento especial para cada clase que desee retornar y eso ya es un problema cuando agregue clases nuevas.

Lo de Novlucker parece un poco mejor pero los controles de los módulos son dinámicos por lo cual al control solo lo llamo "Control" y no con el nombre real del control, por lo tanto las propiedades se pierden y no puedo acceder a ellas:

Control modulo = LoadControl(@"C:\...\modulo.ascx");
controlPrincipal.Controls.Add(modulo);


Si dijera Control1 modulo = ... podría ser porque se hereda todo y le puedo establecer un This propio, pero no puedo adivinar si se incluirá Control1 o Control2 ya que los tipos no se pueden establecer de forma dinámica.

El Benjo

Creo que no me di a entender bien yo en realidad pensaba en algo como esto en las clases de los objetos que vas a crear en la clase Default.aspx, es decir los módulos que quieren la información de config:

Código (vbnet) [Seleccionar]

Public Event ObtenerInfo()

Public Sub RecogerInfo(ByVal Info As TipoDeInformacionQueQuieres)
'Aqui haces lo que quieras con la informacion.
End Sub


Y en el código Default.aspx agregarías (al crear los modulos) un manejador del evento
Código (vbnet) [Seleccionar]
AddHandler ModuloCreado.ObtenerInfo, AddressOf Evento y después la sub:

Código (vbnet) [Seleccionar]

Public Sub Evento()
    'Obtengo la informacion de la instancia unica de la clase config
    ' Por ejemplo: InfoObtenida = ObjetoConfig.Informacion1
    'Despues mando la informacion al modulo que pidio la informacion.
    ModuloCreado.Evento(InfoObtenida)
End Sub


De esta manera tu clase Default.aspx sería la que manejaría todo el tráfico de información entre tus módulos y una única instancia de la clase config.

Espero que eso sea un poco más claro, y desde luego espero que te sirva.
www.es.neftis-ai.com

Sí hay un mejor lenguaje de programación y es ese con el que puedes desarrollar tus objetivos.

Novlucker

#9
Cita de: WHK en 11 Julio 2013, 22:30 PM
Si dijera Control1 modulo = ... podría ser porque se hereda todo y le puedo establecer un This propio, pero no puedo adivinar si se incluirá Control1 o Control2 ya que los tipos no se pueden establecer de forma dinámica.

Lo que debes de hacer es crear una clase que herede de System.Web.UI.UserControl, en esa clase declaras la propiedad que van a tener todos tus controles, luego creas UserControls (ascx), pero le cambias la clase de la que heredan por tu nueva clase.

Al momento de hacer el loadcontrol, ahora puedes castear todos los controles a tu nuevo tipo, un tipo común para todos, y desde ahí utilizar la propiedad :P

Código (csharp) [Seleccionar]
public class BaseUserControl : System.Web.UI.UserControl
{
    public string Nombre
    {
        get { return ViewState["_Nombre"] != null ? ViewState["_Nombre"].ToString() : string.Empty; }
        set { ViewState["_Nombre"] = value; }
    }
}


Código (csharp) [Seleccionar]
public partial class WebUserControl1 : BaseUserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Literal1.Text = this.Nombre;
    }
}


Código (csharp) [Seleccionar]
public partial class _Default : Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        BaseUserControl control = (BaseUserControl)LoadControl("WebUserControl1.ascx");
        control.Nombre = "Novlucker";
        PlaceHolder1.Controls.Add(control);
    }
}


Saludos
Contribuye con la limpieza del foro, reporta los "casos perdidos" a un MOD XD

"Hay dos cosas infinitas: el Universo y la estupidez  humana. Y de la primera no estoy muy seguro."
Albert Einstein