Moved chain building and validation from Mono.Security to System
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / ObjectDataSourceView.cs
1 //
2 // System.Web.UI.WebControls.ObjectDataSourceView
3 //
4 // Authors:
5 //  Lluis Sanchez Gual (lluis@novell.com)
6 //
7 // (C) 2005 Novell, Inc. (http://www.novell.com)
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 #if NET_2_0
32 using System;
33 using System.Reflection;
34 using System.Collections;
35 using System.Collections.Specialized;
36 using System.ComponentModel;
37 using System.IO;
38 using System.Data;
39 using System.Web.Compilation;
40
41 namespace System.Web.UI.WebControls
42 {
43
44         public class ObjectDataSourceView : DataSourceView, IStateManager
45         {
46                 ObjectDataSource owner;
47                 HttpContext context;
48                 Type objectType;
49                 Type dataObjectType;
50
51                 bool convertNullToDBNull = false;
52                 bool enablePaging = false;
53                 string dataObjectTypeName = null;
54                 string filterExpression = null;
55                 string maximumRowsParameterName = null;
56                 string oldValuesParameterFormatString = null;
57                 string deleteMethod = null;
58                 string insertMethod = null;
59                 string selectCountMethod = null;
60                 string selectMethod = null;
61                 string sortParameterName = null;
62                 string startRowIndexParameterName = null;
63                 string typeName = null;
64                 string updateMethod = null;
65
66                 bool isTrackingViewState = false;
67                 ParameterCollection selectParameters;
68                 ParameterCollection updateParameters;
69                 ParameterCollection deleteParameters;
70                 ParameterCollection insertParameters;
71                 ParameterCollection filterParameters;
72                 
73                 static readonly object DeletedEvent = new object();
74                 static readonly object DeletingEvent = new object();
75                 static readonly object FilteringEvent = new object();
76                 static readonly object InsertedEvent = new object();
77                 static readonly object InsertingEvent = new object();
78                 static readonly object ObjectCreatedEvent = new object();
79                 static readonly object ObjectCreatingEvent = new object();
80                 static readonly object ObjectDisposingEvent = new object();
81                 //              static readonly object ResolvingMethodEvent = new object();
82                 static readonly object SelectedEvent = new object();
83                 static readonly object SelectingEvent = new object();
84                 static readonly object UpdatedEvent = new object();
85                 static readonly object UpdatingEvent = new object();
86                 
87                 public ObjectDataSourceView (ObjectDataSource owner, string name, HttpContext context): base (owner, name)
88                 {
89                         this.owner = owner;
90                         this.context = context;
91                 }
92                 
93                 public event ObjectDataSourceStatusEventHandler Deleted {
94                         add { Events.AddHandler (DeletedEvent, value); }
95                         remove { Events.RemoveHandler (DeletedEvent, value); }
96                 }
97                 
98                 public event ObjectDataSourceMethodEventHandler Deleting {
99                         add { Events.AddHandler (DeletingEvent, value); }
100                         remove { Events.RemoveHandler (DeletingEvent, value); }
101                 }
102                 
103                 public event ObjectDataSourceFilteringEventHandler Filtering {
104                         add { Events.AddHandler (FilteringEvent, value); }
105                         remove { Events.RemoveHandler (FilteringEvent, value); }
106                 }
107                 
108                 public event ObjectDataSourceStatusEventHandler Inserted {
109                         add { Events.AddHandler (InsertedEvent, value); }
110                         remove { Events.RemoveHandler (InsertedEvent, value); }
111                 }
112                 
113                 public event ObjectDataSourceMethodEventHandler Inserting {
114                         add { Events.AddHandler (InsertingEvent, value); }
115                         remove { Events.RemoveHandler (InsertingEvent, value); }
116                 }
117                 
118                 public event ObjectDataSourceObjectEventHandler ObjectCreated {
119                         add { Events.AddHandler (ObjectCreatedEvent, value); }
120                         remove { Events.RemoveHandler (ObjectCreatedEvent, value); }
121                 }
122                 
123                 public event ObjectDataSourceObjectEventHandler ObjectCreating {
124                         add { Events.AddHandler (ObjectCreatingEvent, value); }
125                         remove { Events.RemoveHandler (ObjectCreatingEvent, value); }
126                 }
127                 
128                 public event ObjectDataSourceDisposingEventHandler ObjectDisposing {
129                         add { Events.AddHandler (ObjectDisposingEvent, value); }
130                         remove { Events.RemoveHandler (ObjectDisposingEvent, value); }
131                 }
132                 
133                 /*              public event ObjectDataSourceResolvingMethodEventHandler ResolvingMethod {
134                                 add { Events.AddHandler (ResolvingMethodEvent, value); }
135                                 remove { Events.RemoveHandler (ResolvingMethodEvent, value); }
136                                 }
137                 */
138                 public event ObjectDataSourceStatusEventHandler Selected {
139                         add { Events.AddHandler (SelectedEvent, value); }
140                         remove { Events.RemoveHandler (SelectedEvent, value); }
141                 }
142                 
143                 public event ObjectDataSourceSelectingEventHandler Selecting {
144                         add { Events.AddHandler (SelectingEvent, value); }
145                         remove { Events.RemoveHandler (SelectingEvent, value); }
146                 }
147                 
148                 public event ObjectDataSourceStatusEventHandler Updated {
149                         add { Events.AddHandler (UpdatedEvent, value); }
150                         remove { Events.RemoveHandler (UpdatedEvent, value); }
151                 }
152                 
153                 public event ObjectDataSourceMethodEventHandler Updating {
154                         add { Events.AddHandler (UpdatingEvent, value); }
155                         remove { Events.RemoveHandler (UpdatingEvent, value); }
156                 }
157                 
158                 protected virtual void OnDeleted (ObjectDataSourceStatusEventArgs e)
159                 {
160                         if (Events != null) {
161                                 ObjectDataSourceStatusEventHandler eh = (ObjectDataSourceStatusEventHandler) Events [DeletedEvent];
162                                 if (eh != null) eh (this, e);
163                         }
164                 }
165                 
166                 protected virtual void OnDeleting (ObjectDataSourceMethodEventArgs e)
167                 {
168                         if (Events != null) {
169                                 ObjectDataSourceMethodEventHandler eh = (ObjectDataSourceMethodEventHandler) Events [DeletingEvent];
170                                 if (eh != null) eh (this, e);
171                         }
172                 }
173                 
174                 protected virtual void OnFiltering (ObjectDataSourceFilteringEventArgs e)
175                 {
176                         if (Events != null) {
177                                 ObjectDataSourceFilteringEventHandler eh = (ObjectDataSourceFilteringEventHandler) Events [FilteringEvent];
178                                 if (eh != null) eh (this, e);
179                         }
180                 }
181                 
182                 protected virtual void OnInserted (ObjectDataSourceStatusEventArgs e)
183                 {
184                         if (Events != null) {
185                                 ObjectDataSourceStatusEventHandler eh = (ObjectDataSourceStatusEventHandler) Events [InsertedEvent];
186                                 if (eh != null) eh (this, e);
187                         }
188                 }
189                 
190                 protected virtual void OnInserting (ObjectDataSourceMethodEventArgs e)
191                 {
192                         if (Events != null) {
193                                 ObjectDataSourceMethodEventHandler eh = (ObjectDataSourceMethodEventHandler) Events [InsertingEvent];
194                                 if (eh != null) eh (this, e);
195                         }
196                 }
197                 
198                 protected virtual void OnObjectCreated (ObjectDataSourceEventArgs e)
199                 {
200                         if (Events != null) {
201                                 ObjectDataSourceObjectEventHandler eh = (ObjectDataSourceObjectEventHandler) Events [ObjectCreatedEvent];
202                                 if (eh != null) eh (this, e);
203                         }
204                 }
205                 
206                 protected virtual void OnObjectCreating (ObjectDataSourceEventArgs e)
207                 {
208                         if (Events != null) {
209                                 ObjectDataSourceObjectEventHandler eh = (ObjectDataSourceObjectEventHandler) Events [ObjectCreatingEvent];
210                                 if (eh != null) eh (this, e);
211                         }
212                 }
213                 
214                 protected virtual void OnObjectDisposing (ObjectDataSourceDisposingEventArgs e)
215                 {
216                         if (Events != null) {
217                                 ObjectDataSourceDisposingEventHandler eh = (ObjectDataSourceDisposingEventHandler) Events [ObjectDisposingEvent];
218                                 if (eh != null) eh (this, e);
219                         }
220                 }
221                 
222                 /*              protected virtual void OnResolvingMethod (ObjectDataSourceResolvingMethodEventArgs e)
223                                 {
224                                 if (Events != null) {
225                                 ObjectDataSourceResolvingMethodEventHandler eh = (ObjectDataSourceResolvingMethodEventHandler) Events [ResolvingMethodEvent];
226                                 if (eh != null) eh (this, e);
227                                 }
228                                 }
229                 */
230                 
231                 protected virtual void OnSelected (ObjectDataSourceStatusEventArgs e)
232                 {
233                         if (Events != null) {
234                                 ObjectDataSourceStatusEventHandler eh = (ObjectDataSourceStatusEventHandler) Events [SelectedEvent];
235                                 if (eh != null) eh (this, e);
236                         }
237                 }
238                 
239                 protected virtual void OnSelecting (ObjectDataSourceSelectingEventArgs e)
240                 {
241                         if (Events != null) {
242                                 ObjectDataSourceSelectingEventHandler eh = (ObjectDataSourceSelectingEventHandler) Events [SelectingEvent];
243                                 if (eh != null) eh (this, e);
244                         }
245                 }
246                 
247                 protected virtual void OnUpdated (ObjectDataSourceStatusEventArgs e)
248                 {
249                         if (Events != null) {
250                                 ObjectDataSourceStatusEventHandler eh = (ObjectDataSourceStatusEventHandler) Events [UpdatedEvent];
251                                 if (eh != null) eh (this, e);
252                         }
253                 }
254                 
255                 protected virtual void OnUpdating (ObjectDataSourceMethodEventArgs e)
256                 {
257                         if (Events != null) {
258                                 ObjectDataSourceMethodEventHandler eh = (ObjectDataSourceMethodEventHandler) Events [UpdatingEvent];
259                                 if (eh != null) eh (this, e);
260                         }
261                 }
262                 
263                 public override bool CanDelete {
264                         get { return DeleteMethod.Length > 0; }
265                 }
266                 
267                 public override bool CanInsert {
268                         get { return InsertMethod.Length > 0; }
269                 }
270                 
271                 public override bool CanPage {
272                         get { return EnablePaging; }
273                 }
274                 
275                 public override bool CanRetrieveTotalRowCount {
276                         get {
277                                 if( SelectCountMethod.Length > 0)
278                                         return true;
279
280                                 return !EnablePaging;
281                         }
282                 }
283                 
284                 public override bool CanSort {
285                         get { return true; }
286                 }
287                 
288                 public override bool CanUpdate {
289                         get { return UpdateMethod.Length > 0; }
290                 }
291
292                 // LAME SPEC: MSDN says value should be stored in ViewState but tests show otherwise.
293                 ConflictOptions conflictDetection = ConflictOptions.OverwriteChanges;
294                 public ConflictOptions ConflictDetection {
295                         get { return conflictDetection; }
296                         set {
297                                 if (ConflictDetection == value)
298                                         return;
299                                 conflictDetection = value;
300                                 OnDataSourceViewChanged (EventArgs.Empty);
301                         }
302                 }
303
304                 public bool ConvertNullToDBNull {
305                         get { return convertNullToDBNull; }
306                         set { convertNullToDBNull = value; }
307                 }
308
309                 public string DataObjectTypeName {
310                         get {
311                                 return dataObjectTypeName != null ? dataObjectTypeName : string.Empty;
312                         }
313                         set {
314                                 if (DataObjectTypeName == value)
315                                         return;
316                                 dataObjectTypeName = value;
317                                 dataObjectType = null;
318                                 OnDataSourceViewChanged (EventArgs.Empty);
319                         }
320                 }
321
322                 public string DeleteMethod {
323                         get {
324                                 return deleteMethod != null ? deleteMethod : string.Empty;
325                         }
326                         set {
327                                 deleteMethod = value;
328                         }
329                 }
330                 
331                 public ParameterCollection DeleteParameters {
332                         get {
333                                 if (deleteParameters == null) {
334                                         deleteParameters = new ParameterCollection ();
335                                 }
336                                 return deleteParameters;
337                         }
338                 }
339
340                 public bool EnablePaging {
341                         get {
342                                 return enablePaging;
343                         }
344                         set {
345                                 if (EnablePaging == value)
346                                         return;
347                                 enablePaging = value;
348                                 OnDataSourceViewChanged (EventArgs.Empty);
349                         }
350                 }
351
352                 public string FilterExpression {
353                         get {
354                                 return filterExpression != null ? filterExpression : string.Empty;
355                         }
356                         set {
357                                 if (FilterExpression == value)
358                                         return;
359                                 filterExpression = value;
360                                 OnDataSourceViewChanged (EventArgs.Empty);
361                         }
362                 }
363
364                 public ParameterCollection FilterParameters {
365                         get {
366                                 if (filterParameters == null) {
367                                         filterParameters = new ParameterCollection ();
368                                         filterParameters.ParametersChanged += new EventHandler (OnParametersChanged); 
369                                         if (IsTrackingViewState)
370                                                 ((IStateManager)filterParameters).TrackViewState ();
371                                 }
372                                 return filterParameters;
373                         }
374                 }
375
376                 public string InsertMethod {
377                         get {
378                                 return insertMethod != null ? insertMethod : string.Empty;
379                         }
380                         set {
381                                 insertMethod = value;
382                         }
383                 }
384
385                 public ParameterCollection InsertParameters {
386                         get {
387                                 if (insertParameters == null) {
388                                         insertParameters = new ParameterCollection ();
389                                 }
390                                 return insertParameters;
391                         }
392                 }
393
394                 public string MaximumRowsParameterName {
395                         get {
396                                 return maximumRowsParameterName != null ? maximumRowsParameterName : "maximumRows";
397                         }
398                         set {
399                                 if (MaximumRowsParameterName == value)
400                                         return;
401                                 maximumRowsParameterName = value;
402                                 OnDataSourceViewChanged (EventArgs.Empty);
403                         }
404                 }
405
406                 public string OldValuesParameterFormatString {
407                         get {
408                                 return oldValuesParameterFormatString != null ? oldValuesParameterFormatString : "{0}";
409                         }
410                         set {
411                                 if (OldValuesParameterFormatString == value)
412                                         return;
413                                 oldValuesParameterFormatString = value;
414                                 OnDataSourceViewChanged (EventArgs.Empty);
415                         }
416                 }
417
418                 public string SelectCountMethod {
419                         get {
420                                 return selectCountMethod != null ? selectCountMethod : string.Empty;
421                         }
422                         set {
423                                 if (SelectCountMethod == value)
424                                         return;
425                                 selectCountMethod = value;
426                                 OnDataSourceViewChanged (EventArgs.Empty);
427                         }
428                 }
429
430                 public string SelectMethod {
431                         get {
432                                 return selectMethod != null ? selectMethod : string.Empty;
433                         }
434                         set {
435                                 if (SelectMethod == value)
436                                         return;
437                                 selectMethod = value;
438                                 OnDataSourceViewChanged (EventArgs.Empty);
439                         }
440                 }
441
442                 public ParameterCollection SelectParameters {
443                         get {
444                                 if (selectParameters == null) {
445                                         selectParameters = new ParameterCollection ();
446                                         selectParameters.ParametersChanged += new EventHandler (OnParametersChanged); 
447                                         if (IsTrackingViewState)
448                                                 ((IStateManager)selectParameters).TrackViewState ();
449                                 }
450                                 return selectParameters;
451                         }
452                 }
453
454                 public string SortParameterName {
455                         get {
456                                 return sortParameterName != null ? sortParameterName : string.Empty;
457                         }
458                         set {
459                                 sortParameterName = value;
460                         }
461                 }
462
463                 public string StartRowIndexParameterName {
464                         get {
465                                 return startRowIndexParameterName != null ? startRowIndexParameterName : "startRowIndex";
466                         }
467                         set {
468                                 if (StartRowIndexParameterName == value)
469                                         return;
470                                 startRowIndexParameterName = value;
471                                 OnDataSourceViewChanged (EventArgs.Empty);
472                         }
473                 }
474
475                 public string TypeName {
476                         get {
477                                 return typeName != null ? typeName : string.Empty;
478                         }
479                         set {
480                                 if (TypeName == value)
481                                         return;
482                                 typeName = value;
483                                 objectType = null;
484                                 OnDataSourceViewChanged (EventArgs.Empty);
485                         }
486                 }
487
488                 public string UpdateMethod {
489                         get {
490                                 return updateMethod != null ? updateMethod : string.Empty;
491                         }
492                         set {
493                                 updateMethod = value;
494                         }
495                 }
496
497                 public ParameterCollection UpdateParameters {
498                         get {
499                                 if (updateParameters == null) {
500                                         updateParameters = new ParameterCollection ();
501                                 }
502                                 return updateParameters;
503                         }
504                 }
505     
506                 Type ObjectType {
507                         get {
508                                 if (objectType == null) {
509                                         objectType = HttpApplication.LoadType (TypeName);
510                                         if (objectType == null)
511                                                 throw new InvalidOperationException ("Type not found: " + TypeName);
512                                 }
513                                 return objectType;
514                         }
515                 }
516                 
517                 Type DataObjectType {
518                         get {
519                                 if (dataObjectType == null) {
520                                         dataObjectType = HttpApplication.LoadType (DataObjectTypeName);
521                                         if (dataObjectType == null)
522                                                 throw new InvalidOperationException ("Type not found: " + DataObjectTypeName);
523                                 }
524                                 return dataObjectType;
525                         }
526                 }
527                 
528                 public IEnumerable Select (DataSourceSelectArguments arguments)
529                 {
530                         return ExecuteSelect (arguments);
531                 }
532                 
533                 public int Update (IDictionary keys, IDictionary values, IDictionary oldValues)
534                 {
535                         return ExecuteUpdate (keys, values, oldValues);
536                 }
537                 
538                 public int Delete (IDictionary keys, IDictionary oldValues)
539                 {
540                         return ExecuteDelete (keys, oldValues);
541                 }
542                 
543                 public int Insert (IDictionary values)
544                 {
545                         return ExecuteInsert (values);
546                 }
547                 
548                 protected override int ExecuteInsert (IDictionary values)
549                 {
550                         if (!CanInsert)
551                                 throw new NotSupportedException ("Insert operation not supported.");
552                                 
553                         IOrderedDictionary paramValues;
554                         MethodInfo method;
555                         
556                         if (DataObjectTypeName.Length == 0) {
557                                 paramValues = MergeParameterValues (InsertParameters, values, null);
558                                 method = GetObjectMethod (InsertMethod, paramValues, DataObjectMethodType.Insert);
559                         } else {
560                                 method = ResolveDataObjectMethod (InsertMethod, values, null, out paramValues);
561                         }
562                         
563                         ObjectDataSourceMethodEventArgs args = new ObjectDataSourceMethodEventArgs (paramValues);
564                         OnInserting (args);
565                         if (args.Cancel)
566                                 return -1;
567                         
568                         ObjectDataSourceStatusEventArgs rargs = InvokeMethod (method, paramValues);
569                         OnInserted (rargs);
570                         
571                         if (rargs.Exception != null && !rargs.ExceptionHandled)
572                                 throw rargs.Exception;
573
574                         if (owner.EnableCaching)
575                                 owner.Cache.Expire ();
576                         
577                         OnDataSourceViewChanged (EventArgs.Empty);
578
579                         return -1;
580                 }
581
582                 protected override int ExecuteDelete (IDictionary keys, IDictionary oldValues)
583                 {
584                         if (!CanDelete)
585                                 throw new NotSupportedException ("Delete operation not supported.");
586                                 
587                         if (ConflictDetection == ConflictOptions.CompareAllValues && (oldValues == null || oldValues.Count == 0))
588                                 throw new InvalidOperationException ("ConflictDetection is set to CompareAllValues and oldValues collection is null or empty.");
589
590                         IDictionary oldDataValues;
591                         oldDataValues = BuildOldValuesList (keys, oldValues, false);
592                                         
593                         IOrderedDictionary paramValues;
594                         MethodInfo method;
595                         
596                         if (DataObjectTypeName.Length == 0) {
597                                 paramValues = MergeParameterValues (DeleteParameters, null, oldDataValues);
598                                 method = GetObjectMethod (DeleteMethod, paramValues, DataObjectMethodType.Delete);
599                         } else {
600                                 method = ResolveDataObjectMethod (DeleteMethod, oldDataValues, null, out paramValues);
601                         }
602                         
603                         ObjectDataSourceMethodEventArgs args = new ObjectDataSourceMethodEventArgs (paramValues);
604                         OnDeleting (args);
605                         if (args.Cancel)
606                                 return -1;
607                         
608                         ObjectDataSourceStatusEventArgs rargs = InvokeMethod (method, paramValues);
609                         
610                         OnDeleted (rargs);
611                         
612                         if (rargs.Exception != null && !rargs.ExceptionHandled)
613                                 throw rargs.Exception;
614
615                         if (owner.EnableCaching)
616                                 owner.Cache.Expire ();
617                         
618                         OnDataSourceViewChanged (EventArgs.Empty);
619
620                         return -1;
621                 }
622
623                 protected override int ExecuteUpdate (IDictionary keys, IDictionary values, IDictionary oldValues)
624                 {
625                         IOrderedDictionary paramValues;
626                         MethodInfo method;
627
628                         IDictionary oldDataValues;
629                         oldDataValues = BuildOldValuesList (keys, oldValues, true);
630
631                         if (DataObjectTypeName.Length == 0)
632                         {
633                                 IDictionary dataValues;
634                                 dataValues = values;
635                                 paramValues = MergeParameterValues (UpdateParameters, dataValues, oldDataValues);
636                                 method = GetObjectMethod (UpdateMethod, paramValues, DataObjectMethodType.Update);
637                         }
638                         else
639                         {
640                                 if (ConflictDetection != ConflictOptions.CompareAllValues) {
641                                         oldDataValues = null;
642                                 }
643                                 IDictionary dataValues = new Hashtable ();
644                                 if (keys != null) {
645                                         foreach (DictionaryEntry de in keys)
646                                                 dataValues [de.Key] = de.Value;
647                                 }
648                                 if (values != null) {
649                                         foreach (DictionaryEntry de in values)
650                                                 dataValues [de.Key] = de.Value;
651                                 }
652
653                                 method = ResolveDataObjectMethod (UpdateMethod, dataValues, oldDataValues, out paramValues);
654                         }                       
655
656                         ObjectDataSourceMethodEventArgs args = new ObjectDataSourceMethodEventArgs (paramValues);
657                         OnUpdating (args);
658                         if (args.Cancel)
659                                 return -1;
660                         
661                         ObjectDataSourceStatusEventArgs rargs = InvokeMethod (method, paramValues);
662                         OnUpdated (rargs);
663                         
664                         if (rargs.Exception != null && !rargs.ExceptionHandled)
665                                 throw rargs.Exception;
666
667                         if (owner.EnableCaching)
668                                 owner.Cache.Expire ();
669                         
670                         OnDataSourceViewChanged (EventArgs.Empty);
671
672                         return -1;
673                 }
674
675                 IDictionary BuildOldValuesList (IDictionary keys, IDictionary oldValues, bool keysWin) 
676                 {
677                         IDictionary oldDataValues;
678                         if (ConflictDetection == ConflictOptions.CompareAllValues) {
679                                 oldDataValues = new Hashtable ();
680                                 if (keys != null && !keysWin) {
681                                         foreach (DictionaryEntry de in keys)
682                                                 oldDataValues [de.Key] = de.Value;
683                                 }
684                                 if (oldValues != null) {
685                                         foreach (DictionaryEntry de in oldValues)
686                                                 oldDataValues [de.Key] = de.Value;
687                                 }
688                                 if (keys != null && keysWin) {
689                                         foreach (DictionaryEntry de in keys)
690                                                 oldDataValues [de.Key] = de.Value;
691                                 }
692                         }
693                         else {
694                                 oldDataValues = keys;
695                         }
696
697                         return oldDataValues;
698                 }
699
700                 protected internal override IEnumerable ExecuteSelect (DataSourceSelectArguments arguments)
701                 {
702                         arguments.RaiseUnsupportedCapabilitiesError (this);
703
704                         IOrderedDictionary paramValues = MergeParameterValues (SelectParameters, null, null);
705                         ObjectDataSourceSelectingEventArgs args = new ObjectDataSourceSelectingEventArgs (paramValues, arguments, false);
706
707                         object result = null;
708
709                         if (owner.EnableCaching)
710                                 result = owner.Cache.GetCachedObject (SelectMethod, SelectParameters);
711
712                         if (result == null) {
713                                 OnSelecting (args);
714                                 if (args.Cancel)
715                                         return new ArrayList ();
716                                 
717                                 if (CanPage) {
718                                         if (StartRowIndexParameterName.Length == 0)
719                                                 throw new InvalidOperationException ("Paging is enabled, but the StartRowIndexParameterName property is not set.");
720                                         if (MaximumRowsParameterName.Length == 0)
721                                                 throw new InvalidOperationException ("Paging is enabled, but the MaximumRowsParameterName property is not set.");
722                                         paramValues [StartRowIndexParameterName] = arguments.StartRowIndex;
723                                         paramValues [MaximumRowsParameterName] = arguments.MaximumRows;
724                                 }
725
726                                 if (SortParameterName.Length > 0)
727                                         paramValues [SortParameterName] = arguments.SortExpression;
728
729                                 result = InvokeSelect (SelectMethod, paramValues);
730
731                                 if (CanRetrieveTotalRowCount && arguments.RetrieveTotalRowCount)
732                                         arguments.TotalRowCount = QueryTotalRowCount (MergeParameterValues (SelectParameters, null, null), arguments);
733                                 
734                                 if (owner.EnableCaching)
735                                         owner.Cache.SetCachedObject (SelectMethod, SelectParameters, result);
736                         }
737
738                         if (FilterExpression.Length > 0 && !(result is DataGrid || result is DataView || result is DataTable))
739                                 throw new NotSupportedException ("The FilterExpression property was set and the Select method does not return a DataSet, DataTable, or DataView.");
740
741                         if (owner.EnableCaching && result is IDataReader)
742                                 throw new NotSupportedException ("Data source does not support caching objects that implement IDataReader");
743                         
744                         if (result is DataSet) {
745                                 DataSet dset = (DataSet) result;
746                                 if (dset.Tables.Count == 0)
747                                         throw new InvalidOperationException ("The select method returnet a DataSet which doesn't contain any table.");
748                                 result = dset.Tables [0];
749                         }
750                         
751                         if (result is DataTable) {
752                                 DataView dview = new DataView ((DataTable)result);
753                                 if (arguments.SortExpression != null && arguments.SortExpression.Length > 0) {
754                                         dview.Sort = arguments.SortExpression;
755                                 }
756                                 if (FilterExpression.Length > 0) {
757                                         IOrderedDictionary fparams = FilterParameters.GetValues (context, owner);
758                                         ObjectDataSourceFilteringEventArgs fargs = new ObjectDataSourceFilteringEventArgs (fparams);
759                                         OnFiltering (fargs);
760                                         if (!fargs.Cancel) {
761                                                 object[] formatValues = new object [fparams.Count];
762                                                 for (int n=0; n<formatValues.Length; n++) {
763                                                         formatValues [n] = fparams [n];
764                                                         if (formatValues [n] == null) return dview;
765                                                 }
766                                                 dview.RowFilter = string.Format (FilterExpression, formatValues);
767                                         }
768                                 }
769                                 return dview;
770                         }
771                         
772                         if (result is IEnumerable)
773                                 return (IEnumerable) result;
774                         else
775                                 return new object[] {result};
776                 }
777                 
778                 int QueryTotalRowCount (IOrderedDictionary mergedParameters, DataSourceSelectArguments arguments)
779                 {
780                         ObjectDataSourceSelectingEventArgs countArgs = new ObjectDataSourceSelectingEventArgs (mergedParameters, arguments, true);
781                         OnSelecting (countArgs);
782                         if (countArgs.Cancel)
783                                 return 0;
784                         
785                         object count = InvokeSelect (SelectCountMethod, mergedParameters);
786                         return (int) Convert.ChangeType (count, typeof(int));
787                 }
788                 
789                 object InvokeSelect (string methodName, IOrderedDictionary paramValues)
790                 {
791                         MethodInfo method = GetObjectMethod (methodName, paramValues, DataObjectMethodType.Select);
792                         ObjectDataSourceStatusEventArgs rargs = InvokeMethod (method, paramValues);
793                         OnSelected (rargs);
794                         
795                         if (rargs.Exception != null && !rargs.ExceptionHandled)
796                                 throw rargs.Exception;
797
798                         return rargs.ReturnValue;
799                 }
800                 
801                 ObjectDataSourceStatusEventArgs InvokeMethod (MethodInfo method, IOrderedDictionary paramValues)
802                 {
803                         object instance = null;
804
805                         if (!method.IsStatic)
806                                 instance = CreateObjectInstance ();
807
808                         ParameterInfo[] pars = method.GetParameters ();
809                         
810                         ArrayList outParamInfos;
811                         object[] methodArgs = GetParameterArray (pars, paramValues, out outParamInfos); 
812                         
813                         if (methodArgs == null)
814                                 throw CreateMethodException (method.Name, paramValues);
815                                         
816                         object result = null;
817                         Hashtable outParams = null;
818                         
819                         try {
820                                 result = method.Invoke (instance, methodArgs);
821                                 if (outParamInfos != null) {
822                                         outParams = new Hashtable ();
823                                         foreach (ParameterInfo op in outParamInfos)
824                                                 outParams [op.Name] = methodArgs [op.Position];
825                                 }
826                                 return new ObjectDataSourceStatusEventArgs (result, outParams, null);
827                         }
828                         catch (Exception ex) {
829                                 return new ObjectDataSourceStatusEventArgs (result, outParams, ex);
830                         }
831                         finally {
832                                 if (instance != null)
833                                         DisposeObjectInstance (instance);
834                         }
835                 }
836                 
837                 MethodInfo GetObjectMethod (string methodName, IOrderedDictionary parameters, DataObjectMethodType methodType)
838                 {
839                         MemberInfo[] methods = ObjectType.GetMember (methodName, MemberTypes.Method, BindingFlags.Instance | 
840                                                                                  BindingFlags.Static | 
841                                                                                  BindingFlags.Public | 
842                                                                                  BindingFlags.IgnoreCase |
843                                                                                  BindingFlags.FlattenHierarchy);
844                         if (methods.Length > 1) {
845                                 // MSDN: The ObjectDataSource resolves method overloads by method name and number
846                                 // of parameters; the names and types of the parameters are not considered.
847                                 // LAMESPEC: the tests show otherwise
848                                 DataObjectMethodAttribute methodAttribute = null;
849                                 MethodInfo methodInfo = null;
850                                 bool hasConflict = false;
851                                 foreach (MethodInfo me in methods) { // we look for methods only
852                                         ParameterInfo [] pinfos = me.GetParameters ();
853                                         if (pinfos.Length == parameters.Count) {
854                                                 object [] attrs = me.GetCustomAttributes (typeof (DataObjectMethodAttribute), true);
855                                                 DataObjectMethodAttribute domAttr = (attrs != null && attrs.Length > 0) ? (DataObjectMethodAttribute) attrs [0] : null;
856                                                 if (domAttr != null && domAttr.MethodType != methodType)
857                                                         continue;
858
859                                                 bool paramsMatch = true;
860                                                 foreach (ParameterInfo pinfo in pinfos) {
861                                                         if (!parameters.Contains (pinfo.Name)) {
862                                                                 paramsMatch = false;
863                                                                 break;
864                                                         }
865                                                 }
866
867                                                 if (!paramsMatch)
868                                                         continue;
869
870                                                 if (domAttr != null) {
871                                                         if (methodAttribute != null) {
872                                                                 if (methodAttribute.IsDefault) {
873                                                                         if (domAttr.IsDefault) {
874                                                                                 methodInfo = null;
875                                                                                 break; //fail due to a conflict
876                                                                         }
877                                                                         else
878                                                                                 continue; //existing matches better
879                                                                 }
880                                                                 else {
881                                                                         methodInfo = null; //we override
882                                                                         hasConflict = !domAttr.IsDefault;
883                                                                 }
884                                                         }
885                                                         else
886                                                                 methodInfo = null; //we override
887                                                 }
888
889                                                 if (methodInfo == null) {
890                                                         methodAttribute = domAttr;
891                                                         methodInfo = me;
892                                                         continue;
893                                                 }
894
895                                                 hasConflict = true;
896                                         }
897                                 }
898
899                                 if (!hasConflict && methodInfo != null)
900                                         return methodInfo;
901                         }
902                         else if (methods.Length == 1) {
903                                 MethodInfo me = methods[0] as MethodInfo;
904                                 if (me != null && me.GetParameters().Length == parameters.Count)
905                                         return me;
906                         }
907                         
908                         throw CreateMethodException (methodName, parameters);
909                 }
910                 
911                 MethodInfo ResolveDataObjectMethod (string methodName, IDictionary values, IDictionary oldValues, out IOrderedDictionary paramValues)
912                 {
913                         MethodInfo method;
914                         if (oldValues != null)
915                                 method = ObjectType.GetMethod (methodName, new Type[] { DataObjectType, DataObjectType });
916                         else
917                                 method = ObjectType.GetMethod (methodName, new Type[] { DataObjectType });
918                         
919                         if (method == null)
920                                 throw new InvalidOperationException ("ObjectDataSource " + owner.ID + " could not find a method named '" + methodName + "' with parameters of type '" + DataObjectType + "' in '" + ObjectType + "'.");
921
922                         paramValues = new OrderedDictionary (StringComparer.InvariantCultureIgnoreCase);
923                         ParameterInfo[] ps = method.GetParameters ();
924                         
925                         if (oldValues != null) {
926                                 if (FormatOldParameter (ps[0].Name) == ps[1].Name) {
927                                         paramValues [ps[0].Name] = CreateDataObject (values);
928                                         paramValues [ps[1].Name] = CreateDataObject (oldValues);
929                                 } else if (FormatOldParameter (ps[1].Name) == ps[0].Name) {
930                                         paramValues [ps[0].Name] = CreateDataObject (oldValues);
931                                         paramValues [ps[1].Name] = CreateDataObject (values);
932                                 } else
933                                         throw new InvalidOperationException ("Method '" + methodName + "' does not have any parameter that fits the value of OldValuesParameterFormatString.");  
934                         } else {
935                                 paramValues [ps[0].Name] = CreateDataObject (values);
936                         }
937                         return method;
938                 }
939                 
940                 Exception CreateMethodException (string methodName, IOrderedDictionary parameters)
941                 {
942                         string s = "";
943                         foreach (string p in parameters.Keys) {
944                                 s += p + ", ";
945                         }
946                         return new InvalidOperationException ("ObjectDataSource " + owner.ID + " could not find a method named '" + methodName + "' with parameters " + s + "in type '" + ObjectType + "'.");
947                 }
948                 
949                 object CreateDataObject (IDictionary values)
950                 {
951                         object ob = Activator.CreateInstance (DataObjectType);
952                         foreach (DictionaryEntry de in values) {
953                                 PropertyInfo p = DataObjectType.GetProperty ((string)de.Key);
954                                 if (p == null) throw new InvalidOperationException ("Property " + de.Key + " not found in type '" +DataObjectType + "'.");
955                                 object[] attributes = p.GetCustomAttributes (typeof (System.ComponentModel.TypeConverterAttribute),
956                                                                              true);
957                                 Type propertyType = p.PropertyType;
958                                 object value = de.Value;
959                                 object converted = ConvertParameterWithTypeConverter (attributes, propertyType, value);
960                                 if (converted == null)
961                                         converted = ConvertParameter (propertyType, value);
962                                                    
963                                 p.SetValue (ob, converted, null);
964                         }
965                         return ob;
966                 }
967                 
968                 object CreateObjectInstance ()
969                 {
970                         ObjectDataSourceEventArgs args = new ObjectDataSourceEventArgs (null);
971                         OnObjectCreating (args);
972                         
973                         if (args.ObjectInstance != null)
974                                 return args.ObjectInstance;
975                                 
976                         object ob = Activator.CreateInstance (ObjectType);
977                         
978                         args.ObjectInstance = ob;
979                         OnObjectCreated (args);
980                         
981                         return args.ObjectInstance;
982                 }
983                 
984                 void DisposeObjectInstance (object obj)
985                 {
986                         ObjectDataSourceDisposingEventArgs args = new ObjectDataSourceDisposingEventArgs (obj);
987                         OnObjectDisposing (args);
988                         
989                         if (!args.Cancel) {
990                                 IDisposable disp = obj as IDisposable;
991                                 if (disp != null) disp.Dispose ();
992                         }
993                 }
994
995                 object FindValueByName (string name, IDictionary values, bool format)
996                 {
997                         if (values == null)
998                                 return null;
999
1000                         foreach (DictionaryEntry de in values) {
1001                                 string valueName = format == true ? FormatOldParameter (de.Key.ToString ()) : de.Key.ToString ();
1002                                 if (String.Compare (name, valueName, StringComparison.InvariantCultureIgnoreCase) == 0)
1003                                         return values [de.Key];
1004                         }
1005                         return null;
1006                 }
1007
1008                 /// <summary>
1009                 /// Merge the current data item fields with view parameter default values
1010                 /// </summary>
1011                 /// <param name="viewParams">default parameters</param>
1012                 /// <param name="values">new parameters for update and insert</param>
1013                 /// <param name="oldValues">old parameters for update and delete</param>
1014                 /// <param name="allwaysAddNewValues">true for insert, as current item is
1015                 /// irrelevant for insert</param>
1016                 /// <returns>merged values</returns>
1017                 IOrderedDictionary MergeParameterValues (ParameterCollection viewParams, IDictionary values, IDictionary oldValues)
1018                 {
1019                         IOrderedDictionary parametersValues = viewParams.GetValues (context, owner);
1020                         OrderedDictionary mergedValues = new OrderedDictionary (StringComparer.InvariantCultureIgnoreCase);
1021                         foreach (string parameterName in parametersValues.Keys) {
1022                                 mergedValues [parameterName] = parametersValues [parameterName];
1023                                 if (oldValues != null) {
1024                                         object value = FindValueByName (parameterName, oldValues, true);
1025                                         if (value != null) {
1026                                                 object dataValue = viewParams [parameterName].ConvertValue (value);
1027                                                 mergedValues [parameterName] = dataValue;
1028                                         }
1029                                 }
1030
1031                                 if (values != null) {
1032                                         object value = FindValueByName (parameterName, values, false);
1033                                         if (value != null) {
1034                                                 object dataValue = viewParams [parameterName].ConvertValue (value);
1035                                                 mergedValues [parameterName] = dataValue;
1036                                         }
1037                                 }
1038                         }
1039
1040                         if (values != null) {
1041                                 foreach (DictionaryEntry de in values)
1042                                         if (FindValueByName ((string) de.Key, mergedValues, false) == null)
1043                                                 mergedValues [de.Key] = de.Value;
1044                         }
1045
1046                         if (oldValues != null) {
1047                                 foreach (DictionaryEntry de in oldValues) {
1048                                         string oldValueKey = FormatOldParameter ((string) de.Key);
1049                                         if (FindValueByName (oldValueKey, mergedValues, false) == null)
1050                                                 mergedValues [oldValueKey] = de.Value;
1051                                 }
1052                         }
1053
1054                         return mergedValues;
1055                 }
1056                 
1057                 object[] GetParameterArray (ParameterInfo[] methodParams, IOrderedDictionary viewParams, out ArrayList outParamInfos)
1058                 {
1059                         // FIXME: make this case insensitive
1060
1061                         outParamInfos = null;
1062                         object[] values = new object [methodParams.Length];
1063                         
1064                         foreach (ParameterInfo mp in methodParams) {
1065                         
1066                                 // Parameter names must match
1067                                 if (!viewParams.Contains (mp.Name)) return null;
1068                                 
1069                                 values [mp.Position] = ConvertParameter (mp.ParameterType, viewParams [mp.Name]);
1070                                 if (mp.ParameterType.IsByRef) {
1071                                         if (outParamInfos == null) outParamInfos = new ArrayList ();
1072                                         outParamInfos.Add (mp);
1073                                 }
1074                         }
1075                         return values;
1076                 }
1077
1078                 object ConvertParameterWithTypeConverter (object[] attributes, Type targetType, object value)
1079                 {
1080                         if (attributes == null || attributes.Length == 0 || value == null)
1081                                 return null;
1082                         TypeConverterAttribute tca;
1083                         Type converterType;
1084                         TypeConverter converter;
1085                         
1086                         foreach (object a in attributes) {
1087                                 tca = a as TypeConverterAttribute;
1088                                 if (tca == null)
1089                                         continue;
1090                                 converterType = HttpApplication.LoadType (tca.ConverterTypeName, false);
1091                                 if (converterType == null)
1092                                         continue;
1093                                 converter = Activator.CreateInstance (converterType, new object[] {targetType}) as TypeConverter;
1094                                 if (converter == null)
1095                                         continue;
1096                                 if (converter.CanConvertFrom (value.GetType ()))
1097                                         return converter.ConvertFrom (value);
1098                                 else if (converter.CanConvertFrom (typeof (string)))
1099                                         return converter.ConvertFrom (value.ToString ());
1100                         }
1101                         
1102                         return null;
1103                 }
1104                 
1105                 object ConvertParameter (Type targetType, object value)
1106                 {
1107                         return ConvertParameter (Type.GetTypeCode (targetType), value);
1108                 }
1109                 
1110                 object ConvertParameter (TypeCode targetType, object value)
1111                 {
1112                         if (value == null) {
1113                                 if (targetType != TypeCode.Object && targetType != TypeCode.String)
1114                                         value = 0;
1115                                 else if (ConvertNullToDBNull)
1116                                         return DBNull.Value;
1117                         }
1118                         if (targetType == TypeCode.Object || targetType == TypeCode.Empty)
1119                                 return value;
1120                         else
1121                                 return Convert.ChangeType (value, targetType);
1122                 }
1123                 
1124                 string FormatOldParameter (string name)
1125                 {
1126                         string f = OldValuesParameterFormatString;
1127                         if (f.Length > 0)
1128                                 return String.Format (f, name);
1129                         else
1130                                 return name;
1131                 }
1132                 
1133                 void OnParametersChanged (object sender, EventArgs args)
1134                 {
1135                         OnDataSourceViewChanged (EventArgs.Empty);
1136                 }
1137                 
1138                 protected virtual void LoadViewState (object savedState)
1139                 {
1140                         object[] state = (savedState == null) ? new object [5] : (object[]) savedState;
1141                         ((IStateManager)SelectParameters).LoadViewState (state[0]); 
1142                         ((IStateManager)UpdateParameters).LoadViewState (state[1]); 
1143                         ((IStateManager)DeleteParameters).LoadViewState (state[2]); 
1144                         ((IStateManager)InsertParameters).LoadViewState (state[3]); 
1145                         ((IStateManager)FilterParameters).LoadViewState (state[4]); 
1146                 }
1147
1148                 protected virtual object SaveViewState()
1149                 {
1150                         object[] state = new object [5];
1151                         
1152                         if (selectParameters != null)
1153                                 state [0] = ((IStateManager)selectParameters).SaveViewState ();
1154                         if (updateParameters != null)
1155                                 state [1] = ((IStateManager)updateParameters).SaveViewState ();
1156                         if (deleteParameters != null)
1157                                 state [2] = ((IStateManager)deleteParameters).SaveViewState ();
1158                         if (insertParameters != null)
1159                                 state [3] = ((IStateManager)insertParameters).SaveViewState ();
1160                         if (filterParameters != null)
1161                                 state [4] = ((IStateManager)filterParameters).SaveViewState ();
1162                         
1163                         foreach (object ob in state)
1164                                 if (ob != null) return state;
1165                         
1166                         return null;
1167                 }
1168                 
1169                 protected virtual void TrackViewState()
1170                 {
1171                         isTrackingViewState = true;
1172
1173                         if (selectParameters != null) ((IStateManager)selectParameters).TrackViewState ();
1174                         if (filterParameters != null) ((IStateManager)filterParameters).TrackViewState ();
1175                 }
1176                 
1177                 protected bool IsTrackingViewState
1178                 {
1179                         get { return isTrackingViewState; }
1180                 }
1181                 
1182                 
1183                 bool IStateManager.IsTrackingViewState
1184                 {
1185                         get { return IsTrackingViewState; }
1186                 }
1187                 
1188                 void IStateManager.TrackViewState()
1189                 {
1190                         TrackViewState ();
1191                 }
1192                 
1193                 void IStateManager.LoadViewState (object savedState)
1194                 {
1195                         LoadViewState (savedState);
1196                 }
1197
1198                 object IStateManager.SaveViewState()
1199                 {
1200                         return SaveViewState ();
1201                 }
1202         }
1203 }
1204 #endif
1205
1206
1207
1208
1209