[Mono-aspnet-list] How to show dynamic data from npgsql in WebGrid

Andrus kobruleht2 at hot.ee
Sat Jul 26 09:30:01 UTC 2014


In Mono ASP .NET MVC4 application, WebGrid shows npgsql dynamic data last row values in every row.

In Mono code below returns

    ?column?
    B
    B

How to force it to return proper result?

If running in windows under Microsoft .NET it returns proper result:

    ?column?
    A
    B

Controller:

        public ActionResult Test()
        {
            var data = TestData();
            return View("ReportData", new ReportDataViewModel(data, ""));
        }

        IEnumerable<dynamic> TestData()
        {
            using (var connection = new NpgsqlConnection(ConnectionString()))
            {
                connection.Open();
                DbCommand command = (DbCommand)connection.CreateCommand();
                command.CommandText = "select 'A' union select 'B'";
                using (command)
                {
                    IEnumerable<string> columnNames = null;
                    using (DbDataReader reader = command.ExecuteReader())
                    {
                        foreach (DbDataRecord record in reader)
                        {
                            if (columnNames == null)
                                columnNames = GetColumnNames(record);
                            yield return new CustomDynamicRecord(columnNames, record);
                        }
                    }
                }
            }
        }

        static IEnumerable<string> GetColumnNames(DbDataRecord record)
        {
            for (int i = 0; i < record.FieldCount; i++)
            {
                yield return record.GetName(i);
            }
        }

        static string ConnectionString()
        {
            NpgsqlConnectionStringBuilder csb = new NpgsqlConnectionStringBuilder()
            {
                SearchPath = "public",
                Host = "localhost",
                Database = "eeva",
                UserName = "postgres",
                Password = "secret"
            };
            return csb.ConnectionString;
        }


CustomDynamicRecord class is copied from ASP.NET source code with minor modifications:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Diagnostics;
    using System.Dynamic;
    using System.Globalization;
    using System.Linq;
    using WebMatrix.Data.Resources;

    public sealed class CustomDynamicRecord : DynamicObject, ICustomTypeDescriptor
    {
        public CustomDynamicRecord(IEnumerable<string> columnNames, IDataRecord record)
        {
            Columns = columnNames.ToList();
            Record = record;
        }

        public IList<string> Columns { get; private set; }

        private IDataRecord Record { get; set; }

        public object this[string name]
        {
            get
            {
                return GetValue(Record[name]);
            }
        }

        public object this[int index]
        {
            get
            {
                return GetValue(Record[index]);
            }
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            result = this[binder.Name];
            return true;
        }

        static object GetValue(object value)
        {
            if (DBNull.Value == value || value == null)
              return null;
           return value;
        }

        public override IEnumerable<string> GetDynamicMemberNames()
        {
            return Columns;
        }

        private void VerifyColumn(string name)
        {
            if (!Columns.Contains(name, StringComparer.OrdinalIgnoreCase))
            {
                throw new InvalidOperationException(
                    String.Format(CultureInfo.CurrentCulture,
                                  "Invalid Column Name " + name));
            }
        }

        AttributeCollection ICustomTypeDescriptor.GetAttributes()
        {
            return AttributeCollection.Empty;
        }

        string ICustomTypeDescriptor.GetClassName()
        {
            return null;
        }

        string ICustomTypeDescriptor.GetComponentName()
        {
            return null;
        }

        TypeConverter ICustomTypeDescriptor.GetConverter()
        {
            return null;
        }

        EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
        {
            return null;
        }

        PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
        {
            return null;
        }

        object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
        {
            return null;
        }

        EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
        {
            return EventDescriptorCollection.Empty;
        }

        EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
        {
            return EventDescriptorCollection.Empty;
        }

        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
        {
            return ((ICustomTypeDescriptor)this).GetProperties();
        }

        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
        {
            var properties = from columnName in Columns
                             let columnIndex = Record.GetOrdinal(columnName)
                             let type = Record.GetFieldType(columnIndex)
                             select new DynamicPropertyDescriptor(columnName, type);

            return new PropertyDescriptorCollection(properties.ToArray(), readOnly: true);
        }

        object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
        {
            return this;
        }

        private class DynamicPropertyDescriptor : PropertyDescriptor
        {
            private static readonly Attribute[] _empty = new Attribute[0];
            private readonly Type _type;

            public DynamicPropertyDescriptor(string name, Type type)
                : base(name, _empty)
            {
                _type = type;
            }

            public override Type ComponentType
            {
                get { return typeof(EevaDynamicRecord); }
            }

            public override bool IsReadOnly
            {
                get { return true; }
            }

            public override Type PropertyType
            {
                get { return _type; }
            }

            public override bool CanResetValue(object component)
            {
                return false;
            }

            public override object GetValue(object component)
            {
                EevaDynamicRecord record = component as EevaDynamicRecord;
                // REVIEW: Should we throw if the wrong object was passed in?
                if (record != null)
                {
                    return record[Name];
                }
                return null;
            }

            public override void ResetValue(object component)
            {
                throw new InvalidOperationException(
                    String.Format(CultureInfo.CurrentCulture,
                                  "DataResources.RecordIsReadOnly", Name));
            }

            public override void SetValue(object component, object value)
            {
                throw new InvalidOperationException(
                    String.Format(CultureInfo.CurrentCulture,
                                  "DataResources.RecordIsReadOnly", Name));
            }

            public override bool ShouldSerializeValue(object component)
            {
                return false;
            }
        }
    }


View:

    @inherits ViewBase<ViewModels.ReportDataViewModel>
    @using System.Web.Helpers
    
    @{ Layout = null;
     var gd = new WebGrid(source: Model.Rows, canSort: false , rowsPerPage:100 );
    }
    
    <!DOCTYPE html>
    <html>
    <head>
    </head>
    <body>
      @gd.GetHtml()
    </body>
    </html>


Model:

    namespace ViewModels
    {
        public class ReportDataViewModel : ViewModelBase
        {
            public IEnumerable<dynamic> Rows { get; set; }
     
            public ReportDataViewModel(IEnumerable<dynamic> rows)
            {
                Rows = rows;
            }
        }
    }

Posted also in http://stackoverflow.com/questions/24965486/how-to-show-dynamic-data-using-npgsql-in-mono-in-webgrid

Andrus.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ximian.com/pipermail/mono-aspnet-list/attachments/20140726/7a1abec5/attachment-0001.html>


More information about the Mono-aspnet-list mailing list