[ASP.net] Valideren van gegevens / objecten meegeven

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • alex3305
  • Registratie: Januari 2004
  • Laatst online: 15-09 09:10
Misschien een ietwat onduidelijke titel?
Het gaat er eigenlijk om, dat ik een webapplicatie probeer te maken (in ASP.net) waarbij ik graag mijn objecten behoud of meegeef als ik de pagina reload, dus bij het valideren van de gegevens.

Globaal het probleem
Om het even kort en bondig te houden. We hebben van school een opdracht gekregen om in ASP.net een programmeersel te brouwen waarbij we 'online Sudoku' kunnen spelen. Nu heb ik al de oplossingscode, aangezien die aangeleverd werd in de vorm van een COM component. Nu moeten wij dus het frontend maken.

Echter initialiseer ik het component in mijn applicatie dus, waarbij ik dus een object creëer, welke een compleet Sudoku spel bevat. Hiervoor heb ik ook al de frontend voor gemaakt en deze werkt en ziet er goed uit. Nu wil ik echter controleren / valideren of de ingevoerde gegevens juist of onjuist zijn. Hier heb ik een methode voor, maar als ik echter hier een button aan hang dan wordt mijn hele pagina opnieuw geïnitialiseerd, waarbij ik dus mijn spel object 'kwijtraak' en er dus een nieuw spel geïnitieerd moet worden omdat ik anders een NullPointerException krijg.

Waar zou het aan kunnen liggen?
Wat mijn probleem dus is, is dat ik mijn objecten kwijtraak zodra ik de pagina refresh. Als dit niet het geval zou zijn, dan zou ik ermee verder kunnen.

Wat al geprobeerd?
Natuurlijk al redelijk wat gegoogled op termen zoals "ASP.net objects", "ASP.net discarding objects" maar ook "ASP.net validating" en dat soort termen. Toen kwam ik al bij een UpdatePanel uit, wat mij al ietwat hielp, maar nog niet genoeg helaas.

Daarnaast had ik ook al wat op GoT gezocht, maar kwam ik zo snel niets relevants tegen.

Mijn vraagstelling?
Hebben er meer mensen ervaring met dit soort problematiek (vast wel :)) en zouden die zo vriendelijk kunnen zijn mij de juiste richting op te sturen.

Acties:
  • 0 Henk 'm!

  • gorgi_19
  • Registratie: Mei 2002
  • Laatst online: 21:27

gorgi_19

Kruimeltjes zijn weer op :9

* gorgi_19 dol op gokken zonder relevante code :P

Je vergeet te checken op Page.IsPostback in je Page_Load

[ Voor 35% gewijzigd door gorgi_19 op 27-07-2009 19:46 ]

Digitaal onderwijsmateriaal, leermateriaal voor hbo


Acties:
  • 0 Henk 'm!

  • Cascade
  • Registratie: Augustus 2006
  • Laatst online: 16-09 11:44
En Understanding ASP.NET View State

Maarreh... is dit niet echt absolute basis ASP.NET? Maak mij niet wijs dit niet bij een tutorial of lesboek naar voren komt... >:) * uche, m'n ASP.NET is wel een beetje roestig

[ Voor 10% gewijzigd door Cascade op 27-07-2009 20:08 ]


Acties:
  • 0 Henk 'm!

  • gorgi_19
  • Registratie: Mei 2002
  • Laatst online: 21:27

gorgi_19

Kruimeltjes zijn weer op :9

Cascade schreef op maandag 27 juli 2009 @ 20:07:
En Understanding ASP.NET View State

Maarreh... is dit niet echt absolute basis ASP.NET?
Dat hangt er vanaf hoe je de zut toevoegt :P Als je dynamisch controls toevoegd sloop je vrij makkelijk je controlcollection :P

Digitaal onderwijsmateriaal, leermateriaal voor hbo


Acties:
  • 0 Henk 'm!

  • alex3305
  • Registratie: Januari 2004
  • Laatst online: 15-09 09:10
gorgi_19 schreef op maandag 27 juli 2009 @ 19:46:
* gorgi_19 dol op gokken zonder relevante code :P

Je vergeet te checken op Page.IsPostback in je Page_Load
Aangezien ik aannam dat dit toch een generieke vraag zou zijn, had ik bij dit voorbeeld geen generieke code toegevoegd, maar bij deze;

ASP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
using Sudoku;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace WebSudoku {
    public partial class _Default : System.Web.UI.Page {

        private Sudoku.IGame game;
        private TextBox[] tbArray;
        private Table tbl;

        public _Default() {
            tbl = new Table();
            tbArray = new TextBox[81];

            if (!Page.IsPostBack) {
                game = new Sudoku.Game();
                game.create();
            }
        }

        public _Default(IGame game, TextBox[] tbArray, Table tbl) {
            this.game = game;
            this.tbArray = tbArray;
            this.tbl = tbl;
        }

        protected void Page_Load(object sender, EventArgs e) {
            AddTable();
            SetNewGame();
            CheckValues();
        }

        private void AddTable() {
            SudokuFields.Controls.Clear();

            int counter = 0;
            for (int row = 0; row < 9; row++) {
                TableRow tr = new TableRow();
                tbl.Controls.Add(tr);

                for (int col = 0; col < 9; col++) {
                    TableCell td = new TableCell();
                    TextBox tb = new TextBox();

                    tb.BorderColor = System.Drawing.Color.Black;
                    tb.BorderStyle = BorderStyle.Solid;
                    tb.BorderWidth = 1;

                    tb.MaxLength = 1;
                    tb.Width = 20;

                    tb.ID = row.ToString() + col.ToString();

                    td.Controls.Add(tb);
                    tr.Controls.Add(td);

                    tbArray[counter] = tb;
                    counter++;
                }
            }

            SudokuFields.Controls.Add(tbl);
        }

        private void SetNewGame() {
            int value; int row = 0; int col = 0;

            foreach (TextBox tb in tbArray) {
                if (tb.ID == row.ToString() + col.ToString()) {
                    game.get(row + 1, col + 1, out value);
                    tb.Text = value.ToString();
                }

                if (col < 8) {
                    col++;
                }
                else {
                    row++;
                    col = 0;
                }
            }
        }

        private void CheckValues() {
            int value; int row = 0; int col = 0; int counter = 0;

            foreach (TextBox tb in tbArray) {
                tb.BackColor = System.Drawing.Color.White;
            }

            for (int i = 0; i < tbArray.Count(); i++) {
                game.get(row + 1, col + 1, out value);
                TextBox tb = tbArray[i];

                lblWarning.Text = "";

                try {
                    if (tb.ID == row.ToString() + col.ToString()) {
                        if (value > 0 && value.ToString() == tb.Text) {
                            tb.BackColor = System.Drawing.Color.GreenYellow;
                            counter++;
                            tbArray[i] = tb;
                        }
                        else if (Convert.ToInt32(tb.Text) > 0 && value.ToString() != tb.Text) {
                            tb.BackColor = System.Drawing.Color.Beige;
                        }
                        else {

                        }
                    }
                }
                catch(Exception) {
                    lblWarning.Text = "Vul alstublieft alleen getallen in!";
                }

                if (col < 8) {
                    col++;
                }
                else {
                    row++;
                    col = 0;
                }
            }
        }

        protected void btnValidate_Click(object sender, EventArgs e) {
            CheckValues();
        }
    }
}


ASP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebSudoku._Default" %>

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

    <script runat="server">
        
    </script>

<html xmlns="http://www.w3.org/1999/xhtml" >

    <head runat="server">
        <title>Web Sudoku</title>
    </head>
    
    <body style="text-align: center; margin: 0 auto;">
        <h1>Web Sudoku - ASP.net</h1>
        
        <form id="myForm" runat="server">
            <asp:ScriptManager ID="ScriptManager" runat="server" />
            <asp:UpdatePanel ID="myUpdatePanel" runat="server" UpdateMode="Conditional">
                <ContentTemplate>
                    <p>
                        <asp:PlaceHolder id="SudokuFields" runat="server" />
                    </p>
                    
                    <p>
                        <asp:Label ID="lblWarning" runat="server" Text=""></asp:Label>
                    </p>
                    
                    <p>
                        <asp:Button ID="btnValidate" runat="server" Text="Valideren!" />
                    </p>
                </ContentTemplate>
            </asp:UpdatePanel>
        </form>
    </body>
</html>
Cascade schreef op maandag 27 juli 2009 @ 20:07:
En Understanding ASP.NET View State

Maarreh... is dit niet echt absolute basis ASP.NET? Maak mij niet wijs dit niet bij een tutorial of lesboek naar voren komt... >:) * uche, m'n ASP.NET is wel een beetje roestig
Om eerlijk te zijn hebben wij helemaal geen documentatie of boeken gekregen voor dit vak. Het gaat namelijk om Software Engineering. Naast deze opdracht heeft de docent bijvoorbeeld ook een Windows Presentation Foundation opdracht gegeven, waarbij die zelf ook geen documentatie kon aanleveren omdat hijzelf de opdracht niet bedacht had.

Toch bedankt voor de link en ik zal eens lezen.

Overigens wil ik nog wel opmerken dat ik al redelijke ervaring heb met C#, alleen eigenlijk nog geen met ASP.net.

[ Voor 37% gewijzigd door alex3305 op 27-07-2009 20:50 . Reden: Even toch alle code toegevoegd.. ]


Acties:
  • 0 Henk 'm!

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 19-09 10:08

Haan

dotnetter

Het kan aan mij liggen, maar doe je normaal gesproken niet de !Page.IsPostBack check in de Page_Load() :?

offtopic:
wat een rare tijd in het jaar trouwens om nog schoolopdrachten te maken?

Kater? Eerst water, de rest komt later


Acties:
  • 0 Henk 'm!

  • gorgi_19
  • Registratie: Mei 2002
  • Laatst online: 21:27

gorgi_19

Kruimeltjes zijn weer op :9

8)7

Je maakt het jezelf bijzonder lastig :P Waarom dump je niet de 38 t/m 65 in de aspx-pagina zelf, heb je ook geen gezeik met viewstate die gek wordt omdat je je controlcollection overhoop gooit. Houd er rekening mee: webforms != winforms en heeft een volledig andere manier van werken en code opbouw.
Regel 33: AddTable();
Deze moet ALTIJD uitgevoerd worden hoort eigenlijk thuis in CreateChildControls of in Page_Init
Regel 34: SetNewGame();
Deze moet ALLEEN UITGEVOERD WORDEN als er GEEN Page.IsPostback is
Regel 35: CheckValues();
Deze moet ALLEEN UITGEVOERD WORDEN als er WEL een Page.IsPostback is (en eigenlijk veroorzaakt door een click-event van de betreffende button)
Haan schreef op maandag 27 juli 2009 @ 21:25:
Het kan aan mij liggen, maar doe je normaal gesproken niet de !Page.IsPostBack check in de Page_Load() :?

offtopic:
wat een rare tijd in het jaar trouwens om nog schoolopdrachten te maken?
Wel gebruikelijk, maar hoeft niet :) Beetje ook afhankelijk wat je wilt uitvoeren en hoe je bepaalde code-delen (mis / ge)bruikt.

[ Voor 41% gewijzigd door gorgi_19 op 27-07-2009 21:38 ]

Digitaal onderwijsmateriaal, leermateriaal voor hbo


Acties:
  • 0 Henk 'm!

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 19-09 10:08

Haan

dotnetter

gorgi_19 schreef op maandag 27 juli 2009 @ 21:33:

Deze moet ALLEEN UITGEVOERD WORDEN als er WEL een Page.IsPostback is (en eigenlijk veroorzaakt door een click-event van de betreffende button)
Helemaal onderaan staat een handler die dat ook doet. Aanroep in Page_Load kan wel weg inderdaad.
[...]
Wel gebruikelijk, maar hoeft niet :) Beetje ook afhankelijk wat je wilt uitvoeren en hoe je bepaalde code-delen (mis / ge)bruikt.
In dit geval staat ie in ieder geval wel beter in de Page_Load zo te zien ;)

Kater? Eerst water, de rest komt later


Acties:
  • 0 Henk 'm!

  • gorgi_19
  • Registratie: Mei 2002
  • Laatst online: 21:27

gorgi_19

Kruimeltjes zijn weer op :9

Haan schreef op maandag 27 juli 2009 @ 21:37:
[...]

Helemaal onderaan staat een handler die dat ook doet. Aanroep in Page_Load kan wel weg inderdaad.
* gorgi_19 benieuwd of die het uberhaupt doet, er staat niet iets van een serverclick bij de Button code in de HTML :P
In dit geval staat ie in ieder geval wel beter in de Page_Load zo te zien ;)
Neuh... Alle code wordt daarin door elkaar gegooid, als klakloos een check doet in je Page.IsPostback dan doet hij nog steeds niets ;)

Trouwens... Je code nog iets beter gekeken.. ASP.Net kent Validators; in z'n algemeenheid probeer je nu op een winform manier een asp.net pagina op te bouwen. Kan je net zo goed met Request.Form aan de gang gaan.

[ Voor 29% gewijzigd door gorgi_19 op 27-07-2009 21:47 ]

Digitaal onderwijsmateriaal, leermateriaal voor hbo


Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
alex3305, ik zal eerlijk zijn en zeggen dat wat je nu gebouwd hebt een compleet verkeerde aanpak v/h probleem is. Draai je gedachtegang om en denk vanuit de .aspx markup waaraan je kleine stukjes code hangt, niet vanuit de code die markup genereert. Code die markup genereert is alleen dan interessant wanneer je zelf zgn. custom controls gaat maken en ik kan je vertellen dat custom controls maken een kunst an sich is. (Een kunst waarbij fouten en omissies in MSDN de meer complexe onderdelen eigenlijk reduceren tot trial-and-error debugging. Probeer maar eens databinding te combineren met templating op een manier die blijft werken met volle viewstate, om maar eens iets te noemen. Da's niet zo simpel als het lijkt.)


Ik som even een paar dingen puntsgewijs op. Hiermee zou je een globaal idee moeten krijgen hoe je dit zo ongeveer in elkaar zou kunnen steken. Uiteraard werp ik je niet de hele oplossing in de hand; daar doet Tweakers per definitie niet aan voor school opdrachten, geloof ik. Dit hoewel ik die oplossing waarschijnlijk in een kwartiertje in elkaar kan steken: ja het is echt zo simpel als je het eenmaal een keer gedaan hebt.

Stap 1:
Dump die hele tbArray variable. Die heb je niet nodig.

Stap 2:
Declareer in je .aspx bestand met <asp:> tags een table tbSudoku met 3 rows met elk 3 cells.
In elke cell een textbox. Kunnen gewoon simpel de IDs cell1, cell2, cell3, etc. hebben.

Evenzo een button btnValidate om te valideren. Hang daar een onClick event aan.

Stap 3:
Zet in je onClick event een genest for loopje dat die 3x3 table naar een array plat perst, je COM component instantieert, de array door de COM component heen frut om te valideren, de uitvoer terug pakt en de COM component weer sloopt. Dit is belangrijk: COM componenten zijn als ik me goed herinner (ooit eens eerder iets gedaan met Excel Interop, wat een nachtmerrie is...) unmanaged resources. Dwz: je moet ze zelf expliciet vrij geven. De Dispose() method zou hier moeten helpen.

Stap 4:
Output de uitvoer die je COM component uitspuugt ("Geldig" / "Ongeldig", of wat je wilt) via een server side validator en validation summary of als je echt simpel wilt doen: gewoon een asp:Label.

Acties:
  • 0 Henk 'm!

  • gorgi_19
  • Registratie: Mei 2002
  • Laatst online: 21:27

gorgi_19

Kruimeltjes zijn weer op :9

R4gnax schreef op maandag 27 juli 2009 @ 21:47:
Stap 2:
Declareer in je .aspx bestand met <asp:> tags een table tbSudoku met 3 rows met elk 3 cells.
In elke cell een textbox. Kunnen gewoon simpel de IDs cell1, cell2, cell3, etc. hebben.

Evenzo een button btnValidate om te valideren. Hang daar een onClick event aan.
Sudoku is een 9x9 tabel :) Is om die reden ook niet verkeerd om op welke manier dan ook code te genereren, al dan niet met behulp van nested repeaters of dmv een table vullen in code-behind.
Een kunst waarbij fouten en omissies in MSDN de meer complexe onderdelen eigenlijk reduceren tot trial-and-error debugging. Probeer maar eens databinding te combineren met templating op een manier die blijft werken met volle viewstate, om maar eens iets te noemen. Da's niet zo simpel als het lijkt.)
Moah.. An sich valt het wel mee, mits je je strict houdt aan het life cycle en eerst controls creert / toevoegt (en iedere request dit doet) en later pas vult :)

[ Voor 44% gewijzigd door gorgi_19 op 27-07-2009 21:54 ]

Digitaal onderwijsmateriaal, leermateriaal voor hbo


Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
gorgi_19 schreef op maandag 27 juli 2009 @ 21:49:
[...]

Sudoku is een 9x9 tabel :) Is om die reden ook niet verkeerd om op welke manier dan ook code te genereren, al dan niet met behulp van nested repeaters of dmv een table vullen in code-behind.
9x9. Je hebt uiteraard gelijk. Ik weet niet wat me daar helemaal bezielde.

Nested repeaters usw. zou inderdaad ook kunnen werken, maar zelfs een 9x9 table is nog wel in harde markup neer te zetten. Daarmee ga je een newbie dan ook niet gelijk bombarderen met templates, dynamisch ingeladen / opgebouwde control trees en Viewstate perikelen1.

Het is al erg genoeg dat je tijdens je eerste opdracht gelijk gebombardeerd wordt met COM interoperability. (E.e.a. doet me eerlijk gezegd ook overkomen alsof de docent in deze absoluut geen kaas gegeten heeft van de materie die hij/zij moet doceren.)
gorgi_19 schreef op maandag 27 juli 2009 @ 21:49:

[...]

Moah.. An sich valt het wel mee, mits je je strict houdt aan het life cycle en eerst controls creert / toevoegt (en iedere request dit doet) en later pas vult :)
Ja. Maar DataBind() en CreateChildControls() werken zo dus niet. Je zult tijdens het databinden je child controls moeten vernietigen en hercreeëren adhv je DataSource property. Wat als je geen datasource toegekend hebt, maar wel data in je ViewState hebt (uit een postback)? Wat als er bepaalde templates (ITemplate) wel/niet ingevuld zijn in de markup?

Bouw maar eens voor een hierarchisch gebonden data grid met verschillende soorten data rows waarvan de structuur behouden blijft in viewstate en tijdens een postback gebruikt kan worden om de grid te hercreeëren zonder het opnieuw aanspreken van de originele datasource. Dan wordt het een stukje moeilijker. Helemaal als je alles ook nog 'ns overgiet met templated kolom headers, data row grouperingen, etc.

Zoals ik al zei: de meer complexe onderdelen, waar je al deze cases moet combineren en tegelijkertijd moet ondersteunen. Da's behoorlijk non-triviaal om volledig dekkend te krijgen.

Let wel: Ik heb het hier over custom controls, niet user controls.


1Hoewel; sinds 2.0 is dat eigenlijk ook goed te doen, mits je alles tijdens Page_Load herbouwt en zorg draagt dat alle IDs voor alle controls stabiel blijven..

[ Voor 37% gewijzigd door R4gnax op 27-07-2009 22:11 ]


Acties:
  • 0 Henk 'm!

  • alex3305
  • Registratie: Januari 2004
  • Laatst online: 15-09 09:10
Op aanwijzingen van hierboven even een 'code revisie' gedaan, waarbij het nog wel allemaal in C# code gegenereerd wordt, maar waar het wat logischer is ingedeeld. Even de vernieuwde methodes:

ASP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<body>
        <div>
            <h1>WebSudoku</h1>
            <h2>Sudoku in ASP.net</h2>
            
            <form id="myForm" runat="server">
                <asp:ScriptManager ID="ScriptManager" runat="server" />
                <asp:UpdatePanel ID="myUpdatePanel" runat="server" UpdateMode="Conditional">
                    <ContentTemplate>
                        <p>
                            <asp:PlaceHolder ID="gamePlaceHolder" runat="server"></asp:PlaceHolder>
                        </p>
                        <p>
                            <asp:Button ID="btnValidate" runat="server" onclick="btnValidate_Click" 
                                Text="Valideren!" />
                        </p>
                        <p>
                            <asp:Label ID="lblWarning" runat="server" Text="Spel goed gestart"></asp:Label>
                        </p>
                    </ContentTemplate>
                </asp:UpdatePanel>
            </form> 
        </div>
    </body>


C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[... zelfde als boven ...]
#region Events
        protected override void OnInit(EventArgs e) {
            AddTable();
        }

        protected void Page_Load(object sender, EventArgs e) {
            if (!Page.IsPostBack) {
                SetNewGame();
                CheckValues();
            }
            else {
                CheckValues();
            }
        }

        protected void btnValidate_Click(object sender, EventArgs e) {
            CheckValues();
        }
        #endregion
[... zelfde als boven ...]


Het probleem wat ik nu heb is dat wanneer ik de button klik ik een NullPointerException krijg op het game object wat op de een of andere manier niet behouden kan blijven of iets dergelijks.

Als ik dan wel een GameCreate() aanroep, klopt er dus niets meer van mijn Sudoku velden. Het gaat er dus voor mij om dat het game object onthouden wordt, bewaard blijft op de server, whatever. En daar kom ik dus niet helemaal uit...
Het is al erg genoeg dat je tijdens je eerste opdracht gelijk gebombardeerd wordt met COM interoperability. (E.e.a. doet me eerlijk gezegd ook overkomen alsof de docent in deze absoluut geen kaas gegeten heeft van de materie die hij/zij moet doceren.)
Zoals ik daarstraks al aangaf, dit is dus het geval. Mijn docent doet deze opdracht voor het eerst samen met een WPF opdracht, waar hij geen verstand van heeft. Hij kent eigenlijk alleen Java (qua programmeertaal) en wat C#, want hij is zelf eigenlijk meer ontwerper van software en systemen. Overigens heb ik dan wel weer genoeg ervaring met C# om met COM componenten overweg te kunnen, maar dan ook alleen in C# :9

[ Voor 13% gewijzigd door alex3305 op 27-07-2009 22:04 ]


Acties:
  • 0 Henk 'm!

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 19-09 10:08

Haan

dotnetter

Een Exception opvangen om te checken of er getallen zijn in gevuld is trouwens ook niet zo heel netjes..de generieke Exception vangen is sowieso eigenlijk altijd bad practice Daar is bijvoorbeeld int.TryParse voor uitgevonden :) Maar nog veel mooier is om aan de textboxen een Validator te hangen die meteen al checkt of er wel een getal is ingevuld, zoals gorgi_19 al zei.

[ Voor 11% gewijzigd door Haan op 27-07-2009 22:12 ]

Kater? Eerst water, de rest komt later


Acties:
  • 0 Henk 'm!

  • alex3305
  • Registratie: Januari 2004
  • Laatst online: 15-09 09:10
Haan, helemaaaaal met je eens, alleen wil ik nu eerst weten hoe ik het game object kan behouden, aangezien die andere dingen niet 100% nodig zijn om de applicatie te laten werken zeg maar.

EDIT: Nog even aan het testen geweest, maar het game object (zie bovenstaand) wordt gewoon fijn genullified als ik op de Valideren knop klik. Zelf al geprobeerd het game object in de Page_Load of in the OnClick mee te geven, maar heeft totaal geen nut...

EDIT 2: Inmiddels heb ik het probleem op kunnen lossen doordat ik iets met Sessions had gevonden. De 'uiteindelijke' code is er vooralsnog zo uit te komen zien;

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#region Events
protected void Page_Load(object sender, EventArgs e) {
    AddTable();

    if (!Page.IsPostBack) {
        SetNewGame();
        CheckValues();
    }
}

protected void btnValidate_Click(object sender, EventArgs e) {
    for (int i = 0; i < Session.Count; i++) {
        switch (Session.Keys[i]) {
            case "game": this.game = (Sudoku.IGame)Session[i]; break;
            case "table": this.tbl = (Table)Session[i]; break;
            case "textBoxArray": this.tbArray = (TextBox[])Session[i]; break;
        }
    }

    CheckValues();
}
#endregion

// Andere, veranderde code

private void SetNewGame() {
    game = new Sudoku.Game();
    game.create();

    int value; int row = 0; int col = 0;

    foreach (TextBox tb in tbArray) {
        if (tb.ID == row.ToString() + col.ToString()) {
            game.get(row + 1, col + 1, out value);
            tb.Text = value.ToString();
        }

        if (col < 8) {
            col++;
        }
        else {
            row++;
            col = 0;
        }
    }

    Session.Add("game", game);
    Session.Add("table", tbl);
    Session.Add("textBoxArray", tbArray);
}


De rest van de code is gewoon hetzelfde gebleven. In ieder geval wil ik iedereen bedanken voor de hulp en het meedenken.

[ Voor 102% gewijzigd door alex3305 op 27-07-2009 23:17 ]


Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
alex3305 schreef op maandag 27 juli 2009 @ 22:20:

[...]

EDIT 2: Inmiddels heb ik het probleem op kunnen lossen doordat ik iets met Sessions had gevonden. De 'uiteindelijke' code is er vooralsnog zo uit te komen zien;

[...]

De rest van de code is gewoon hetzelfde gebleven. In ieder geval wil ik iedereen bedanken voor de hulp en het meedenken.
Ja, ik was er al bang voor. Inderdaad: je instantieert de Sudoku 'game' gedurende de initiële request en cached die in de sessie om zo je game 'levend' te houden. Fout, fout, fout. Als je inderdaad al eens eerder met COM gewerkt hebt in .NET, dan moet je toch zeker weten dat je die componenten correct vrij moet gaan geven. Doe je dat niet, dan krijg je een grandioos geheugen lek!

Jouw Session.Add() gooit een objref naar je COM object de sessie in. Die sessie blijft standaard een x aantal minuten bestaan en wordt dan automatisch vrijgegeven. Op dat moment ben je de objref naar het COM object kwijt, maar is het COM object zelf nog niet vrij gegeven of stop gezet. Dat gebeurt alleen correct als je op het juiste moment Marshal.ReleaseComObject() aanroept en dat kun je niet zomaar aan de .NET garbage collector overlaten. Je krijgt daar echter in de standaard lifecycle geen kans toe.

Initieel zou je denken dat je het SessionEnd event in global.asax kunt gebruiken om dat af te handelen, maar wacht: wat doe je wanneer IIS je application pool wil recyclen? Dan wordt SessionEnd namelijk niet betrouwbaar aangeroepen en blijft het probleem dus bestaan. (Afhankelijk van je applicatie model krijg je zelfs een aantal ruwe ThreadAbortExceptions voor je kiezen uit asynchrone BackgroundWorker threads.)

Je kunt er uiteraard voor kiezen om het probleem te negeren. Dat geheugen komt tenslotte weer vrij met een complete recycle van de applicatie. Oh nee, wacht: toch niet. Het COM object draait typisch in een ander proces dan het asp.net worker process, wat er voor zorgt dat je wanneer je de objref pointer kwijt bent, effectief een compleet ge-orphaned geheugenlek gemaakt hebt. Het geheugen kan dan dus niet meer (automatisch) gereclaimed kan worden. Je moet dan handmatig het COM process afschieten, of in het slechtste geval de server herstarten.


Vandaar dat ik dus ook zei om de textboxes in de .aspx file als leidend model te gebruiken en niet de array en de daaraan aangesloten COM component: In het onclick event van je validatie knopje druk je je textboxes plat naar een array, je maakt een instantie van dat COM object aan, je frot dat array door je COM object heen en daarna schiet je dat COM object ook weer expliciet af. Wil je de toestand opgeslagen houden, dan moet je dat buiten dat COM object regelen in managed .NET code.


Ik hoop dan ook voor je, dat die gare COM component niet alleen die default constructor heeft. (Een constructor die intern zelf een nieuwe willekeurige Sudoku genereert?) Is dat wel het enige wat de component aan boord heeft, dan zul je een eigen management klasse moeten maken die instanties van die COM component bij houdt en ze allemaal met Marshal.ReleaseComObject() vrij kan geven zodra de bijhorende sessie eindigt of zodra de applicatie pool gerecycled wordt. Welke van de twee is afhankelijk van welke het eerste plaats vindt. Fijn daaraan is dan weer dat het recyclen van de applicatie kan starten terwijl SessionEnd plaats aan het vinden is... Daarnaast is het recyclen ook nog eens niet betrouwbaar te detecteren zonder een interop met IIS op te zetten via een implementatie van de IRegisterObject interface.


Voel je de bui inmiddels al hangen? |:(

De moraal van het verhaal is simpel: gebruik unmanaged resources (COM, database connecties, filestreams, etc.) slechts op een stateless manier of gebruik ze niet.

[ Voor 8% gewijzigd door R4gnax op 28-07-2009 00:41 ]

Pagina: 1