2012-08-28 75 views
6

W WebControl, mam właściwość Filters zdefiniowane tak:Czy istnieje sposób przechowywania anonimowego uczestnika w stanie widoku?

public Dictionary<string, Func<T, bool>> Filters 
{ 
    get 
    { 
     Dictionary<string, Func<T, bool>> filters = 
       (Dictionary<string, Func<T, bool>>)ViewState["filters"]; 
     if (filters == null) 
     { 
      filters = new Dictionary<string, Func<T, bool>>(); 
      ViewState["filters"] = filters; 
     } 
     return filters; 
    } 
} 

Ten WebControl jest DataSource, stworzyłem tę właściwość, ponieważ chcę mieć możliwośc filtrować dane łatwo, np

//in page load  
DataSource.Filters.Add("userid", u => u.UserID == 8); 

działa świetnie, jednak w przypadku zmiany kodu do tego:

//in page load  
int userId = int.Parse(DdlUsers.SelectedValue); 
DataSource.Filters.Add("userid", u => u.UserID == userId); 

nie Wor ks już, otrzymuję ten błąd:

Wpisz System.Web.UI.Page w zestawie "..." nie jest oznaczony jako z możliwością serializowania.

Co się stało:

  1. The serializatora skontrolować słownika. Widzi, że zawiera anonimowego delegata (lambda).
  2. Ponieważ delegat jest zdefiniowany w klasie, próbuje serializować całą klasę, w tym przypadku System.Web.UI.Page
  3. Ta klasa nie jest oznaczona jako serializable
  4. zgłasza wyjątek ze względu 3.

Czy istnieje wygodne rozwiązanie aby rozwiązać ten problem? Nie mogę oznaczyć wszystkich stron internetowych, z których korzystam ze źródła danych jako [serializowalne] z oczywistych powodów.


EDIT 1: coś, czego nie rozumiem. Jeśli przechowuję obiekt Dictionary w obiekcie Session (który używa BinaryFormatter vs LosFormatter dla ViewState), działa! Nie mam pojęcia, jak to jest możliwe. Może BinaryFormatter może serializować dowolne zajęcia, nawet te, które nie są [serializable]?


EDIT 2: najmniejsza kod do odtworzenia problemu:

void test() 
{ 
    Test test = new Test(); 
    string param1 = "parametertopass"; 
    test.MyEvent +=() => Console.WriteLine(param1); 

    using (MemoryStream ms = new MemoryStream()) 
    { 
     BinaryFormatter bf = new BinaryFormatter(); 
     bf.Serialize(ms, test); //bang 
    } 
} 

[Serializable] 
public class Test 
{ 
    public event Action MyEvent; 
} 
+0

"Działa, nie mam pojęcia jak ...": dane sesji pozostają po stronie serwera, w pamięci. Zacznie się łamać po przejściu na 2 serwery. –

+0

thx za informacje – tigrou

Odpowiedz

0

znalazłem rozwiązanie, oto jak to zrobiłem:

I zmodyfikowany słownik definicji takiego:

Dictionary<string, KeyValuePair<Func<T, object[], bool>, object[]>> 

(KeyValuePair jest serializacji, podobnie jak Dictionary)

i stworzył nowa funkcja Add():

public void Add(string key, Func<T, object[], bool> filter, params object[] args) 
{ 
    this.Add(key, new KeyValuePair<Func<T, object[], bool>, object[]> 
      (filter, args)); 
} 

Teraz filtry mogą być ustawione w ten sposób:

int userId = int.Parse(DdlUsers.SelectedValue); 
DataSource.Filters.Add("userid", (u, args) => u.UserID == (int)args[0], userId); 

to działa, bo teraz złapanych zmienne nie są już częścią delegat, ale biorąc pod uwagę jak parametrów delegata.

4

dobre pytanie. Mogę potwierdzić twoją diagnozę (z jedną małą poprawką: infrastruktura próbuje serializować klasę zamknięcia, która prawdopodobnie zawiera odniesienie do twojej strony).

Można zdefiniować własną klasę zamknięcia i mają to w odcinkach:

[Serializable] class Closure { int userId; bool Filter(User u) { ... } }; 

To nie jest wygodne, choć.

Proponuję użyć innego wzorca: Nie serializuj "kodu".Serializacji danych wykorzystywanych przez filtr:

class FilterSettings { int userId; int someOtherFiler; string sortOrder; ... } 

Chociaż nie mogę wskazać dokładnej przyczyny, wolałbym, że intuicyjnie wie, że jest lepszym rozwiązaniem.

+0

Dziękuję za odpowiedź. Nie jestem pewien, jak będzie działała druga propozycja. Kto stworzy instancję klasy FilterSettings i zatrzyma ją? Czy na stronie nie ma ryzyka, że ​​serializator również dotrze do strony? Czy możesz podać więcej kodu o tym, jak używać tego rozwiązania? – tigrou

+0

Przechowywanie klasy, której pola dokładnie kontrolujesz, nigdy nie będą odwoływały się do strony. Serializator nie może uzyskać dostępu do strony począwszy od pozycji Zamknięcie lub Ustawienia filtru. – usr

+0

Nadal nie mogę sprawić, żeby działało, nawet z twoimi sugestiami. Dodałem próbkę kodu u dołu pytania, która będzie odtworzyć problem. Czy możesz rzucić okiem i dać mi wskazówkę? – tigrou