Any possiblity that 5.8 has an issue with attributes?

I am using version 5.8 from Nuget and on my last rebuild the DataTypeAttribute is no longer being emitted correctly. It is being emitted empty [DataType].

Derek

The reflection logic to infer attributes was modified which could affect it, can you please provide a complete example showing the issue.

Trying to upload a set of demos (service and client) is there a trick :)?

I hope this is enough to go by. I have a set of demos that I can send.

The code from Configure is

public override void Configure(Container container)
{
    var nativeTypes = GetPlugin<NativeTypesFeature>();
    nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(DisplayAttribute));
    nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(DisplayColumnAttribute));
    nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(DisplayFormatAttribute));
    nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(DataTypeAttribute));
    nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(EditableAttribute));
    nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(ServiceStack.DataAnnotations.PrimaryKeyAttribute));
    nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(ServiceStack.DataAnnotations.AutoIncrementAttribute));
    nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(ServiceStack.DataAnnotations.AutoIdAttribute));
    nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(System.ComponentModel.BindableAttribute));
    nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(AssociationAttribute));

    nativeTypes.ExportAttribute<DisplayAttribute>(x =>
    {
        var metadata = nativeTypes.GetGenerator().ToMetadataAttribute(x);
        try
        {
            var attr = (DisplayAttribute)x;
            if (attr.GetAutoGenerateField() == null || (attr.GetAutoGenerateField().HasValue && !attr.GetAutoGenerateField().Value))
                metadata.Args.Add(new MetadataPropertyType { Name = nameof(DisplayAttribute.AutoGenerateField), TypeNamespace = "System", Type = nameof(Boolean), Value = "false" });
            return metadata;
        }
        catch (Exception ex)
        {

        }
        finally
        {
        }
        return metadata;
    });
}

Emitted class is

public partial class PhysicalCount
{
    [Display(AutoGenerateFilter=true, Order=1, ShortName="Id", AutoGenerateField=false)]
    [AutoIncrement]
    public virtual int Id { get; set; }

    [Display(AutoGenerateFilter=true, Order=1, ShortName="ItemNumber", AutoGenerateField=false)]
    public virtual string ItemNumber { get; set; }

    [Display(AutoGenerateFilter=true, Order=2, ShortName="WarehouseCode", AutoGenerateField=false)]
    public virtual string WarehouseCode { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=3, ShortName="Qty")]
    public virtual int? QtyOnHand { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=4, ShortName="Lot Serial")]
    public virtual string LotSerial { get; set; }

    [Display(AutoGenerateFilter=true, Order=5, ShortName="LocationCode", AutoGenerateField=false)]
    public virtual string LocationCode { get; set; }

    [Display(AutoGenerateFilter=true, Order=6, ShortName="Device ID", AutoGenerateField=false)]
    public virtual string DeviceID { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=7, ShortName="Counted")]
    [DataType]
    [DisplayFormat(ConvertEmptyStringToNull=true, DataFormatString="MM/dd/yyyy HH:mm:ss", HtmlEncode=true)]
    public virtual DateTime CountDate { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=8, ShortName="Counted By")]
    public virtual string DeviceUser { get; set; }

    [Display(Order=9, ShortName="BatchKey", AutoGenerateField=false)]
    public virtual int? BatchKey { get; set; }

    [Display(AutoGenerateField=true, Order=-1, ShortName="Item")]
    [Association("Item.ItemID", "ItemKey", "ItemKey")]
    public virtual int ItemKey { get; set; }

    [Display(Order=-1, ShortName="Whse", AutoGenerateField=false)]
    public virtual int WhseKey { get; set; }

    [Display(AutoGenerateField=true, Order=-1, ShortName="Bin ID")]
    [Association("WarehouseBin.WhseBinID", "WhseBinKey", "WhseBinKey")]
    public virtual int WhseBinKey { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=4, ShortName="Expiration Date")]
    [DataType]
    [DisplayFormat(ConvertEmptyStringToNull=true, DataFormatString="MM/yyyy", HtmlEncode=true)]
    public virtual DateTime? ExpirationDate { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=14, ShortName="Updated")]
    [DataType]
    [DisplayFormat(ConvertEmptyStringToNull=true, DataFormatString="MM/dd/yyyy HH:mm:ss", HtmlEncode=true)]
    public virtual DateTime? UpdateDate { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=15, ShortName="Updated By")]
    public virtual string UpdatedBy { get; set; }
}

Type class from service is

using ServiceStack;
using ServiceStack.DataAnnotations;
using System;
using System.ComponentModel.DataAnnotations;

namespace DemoDataService.ServiceModel.Types
{
	[Alias("PhysicalCount")] 
	[Schema("Allocation.dbo")]
	[NamedConnection("Allocation")]
	public class PhysicalCount 
	{
        [Display(AutoGenerateField = false, AutoGenerateFilter = true, ShortName = "Id", Order = 1)]
        [AutoIncrement]
        public int Id { get; set; }
		[Display(AutoGenerateField = false, AutoGenerateFilter = true, ShortName= "ItemNumber", Order=1)]
		public string ItemNumber { get; set;}
		
		[Display(AutoGenerateField = false, AutoGenerateFilter = true, ShortName= "WarehouseCode", Order=2)]
        public string WarehouseCode { get; set;}
		
		[Display(AutoGenerateField = true, AutoGenerateFilter = true, ShortName= "Qty", Order=3)]
		public int? QtyOnHand { get; set;}
		
		[Display(AutoGenerateField = true, AutoGenerateFilter = true, ShortName= "Lot Serial", Order=4)]
		public string LotSerial { get; set;}
		
		[Display(AutoGenerateField = false, AutoGenerateFilter = true, ShortName= "LocationCode", Order=5)]
        public string LocationCode { get; set;}
		
		[Display(AutoGenerateField = false, AutoGenerateFilter = true, ShortName= "Device ID", Order=6)]
		public string DeviceID { get; set;}
		
		[Display(AutoGenerateField = true, AutoGenerateFilter = true, ShortName= "Counted", Order=7)]
        [DataType(DataType.DateTime)]
        [DisplayFormat(DataFormatString = "MM/dd/yyyy HH:mm:ss")]
		public DateTime CountDate { get; set;}
		
		[Display(AutoGenerateField = true, AutoGenerateFilter = true, ShortName= "Counted By", Order=8)]
		public string DeviceUser { get; set;}
		
		[Display(AutoGenerateField = false, AutoGenerateFilter = false, ShortName= "BatchKey", Order=9)]
        public int? BatchKey { get; set;}
		
		[Display(AutoGenerateField = true, AutoGenerateFilter = false, ShortName= "Item", Order=-1)]
        [Association(name:"Item.ItemID", thisKey:"ItemKey", otherKey:"ItemKey")]
        public int ItemKey { get; set;}
		
		[Display(AutoGenerateField = false, AutoGenerateFilter = false, ShortName= "Whse", Order=-1)]
        public int WhseKey { get; set;}
		
		[Display(AutoGenerateField = true, AutoGenerateFilter = false, ShortName= "Bin ID", Order=-1)]
        [Association(name: "WarehouseBin.WhseBinID", thisKey: "WhseBinKey", otherKey: "WhseBinKey")]
        public int WhseBinKey { get; set;}
		
		[Display(AutoGenerateField = true, AutoGenerateFilter = true, ShortName= "Expiration Date", Order=4)]
        [DataType(DataType.DateTime)]
        [DisplayFormat(DataFormatString = "MM/yyyy")]
        public DateTime? ExpirationDate { get; set;}
		
		[Display(AutoGenerateField = true, AutoGenerateFilter = true, ShortName= "Updated", Order=14)]
        [DataType(DataType.DateTime)]
        [DisplayFormat(DataFormatString = "MM/dd/yyyy HH:mm:ss")]
        public DateTime? UpdateDate { get; set;}
		
		[Display(AutoGenerateField = true, AutoGenerateFilter = true, ShortName= "Updated By", Order=15)]
		public string UpdatedBy { get; set;}

	}
}

What’s the definition of the DataType enum, is DateTime the default (i.e. 0) value?

This is what I see.

public enum DataType
{
//
// Summary:
// Represents a custom data type.
Custom = 0,
//
// Summary:
// Represents an instant in time, expressed as a date and time of day.
DateTime = 1,
//
// Summary:
// Represents a date value.
Date = 2,
//
// Summary:
// Represents a time value.
Time = 3,
//
// Summary:
// Represents a continuous time during which an object exists.
Duration = 4,
//
// Summary:
// Represents a phone number value.
PhoneNumber = 5,
//
// Summary:
// Represents a currency value.
Currency = 6,
//
// Summary:
// Represents text that is displayed.
Text = 7,
//
// Summary:
// Represents an HTML file.
Html = 8,
//
// Summary:
// Represents multi-line text.
MultilineText = 9,
//
// Summary:
// Represents an e-mail address.
EmailAddress = 10,
//
// Summary:
// Represent a password value.
Password = 11,
//
// Summary:
// Represents a URL value.
Url = 12,
//
// Summary:
// Represents a URL to an image.
ImageUrl = 13,
//
// Summary:
// Represents a credit card number.
CreditCard = 14,
//
// Summary:
// Represents a postal code.
PostalCode = 15,
//
// Summary:
// Represents file upload data type.
Upload = 16
}

I’ve found no way to repro this, I’ve tried with the latest sources on GitHub master, v5.7.1 and the just released v5.8, with your custom NativeTypesFeature configuration and PhysicalCount class, they’re all emitting the [DataType] with [DataType(DataType.DateTime)], i.e:

public partial class PhysicalCount
{
    [Display(AutoGenerateFilter=true, Order=1, ShortName="Id", AutoGenerateField=false)]
    [AutoIncrement]
    public virtual int Id { get; set; }

    [Display(AutoGenerateFilter=true, Order=1, ShortName="ItemNumber", AutoGenerateField=false)]
    public virtual string ItemNumber { get; set; }

    [Display(AutoGenerateFilter=true, Order=2, ShortName="WarehouseCode", AutoGenerateField=false)]
    public virtual string WarehouseCode { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=3, ShortName="Qty")]
    public virtual int? QtyOnHand { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=4, ShortName="Lot Serial")]
    public virtual string LotSerial { get; set; }

    [Display(AutoGenerateFilter=true, Order=5, ShortName="LocationCode", AutoGenerateField=false)]
    public virtual string LocationCode { get; set; }

    [Display(AutoGenerateFilter=true, Order=6, ShortName="Device ID", AutoGenerateField=false)]
    public virtual string DeviceID { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=7, ShortName="Counted")]
    [DataType(DataType.DateTime)]
    [DisplayFormat(ConvertEmptyStringToNull=true, DataFormatString="MM/dd/yyyy HH:mm:ss", HtmlEncode=true)]
    public virtual DateTime CountDate { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=8, ShortName="Counted By")]
    public virtual string DeviceUser { get; set; }

    [Display(Order=9, ShortName="BatchKey", AutoGenerateField=false)]
    public virtual int? BatchKey { get; set; }

    [Display(AutoGenerateField=true, Order=-1, ShortName="Item")]
    [Association("Item.ItemID", "ItemKey", "ItemKey")]
    public virtual int ItemKey { get; set; }

    [Display(Order=-1, ShortName="Whse", AutoGenerateField=false)]
    public virtual int WhseKey { get; set; }

    [Display(AutoGenerateField=true, Order=-1, ShortName="Bin ID")]
    [Association("WarehouseBin.WhseBinID", "WhseBinKey", "WhseBinKey")]
    public virtual int WhseBinKey { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=4, ShortName="Expiration Date")]
    [DataType(DataType.DateTime)]
    [DisplayFormat(ConvertEmptyStringToNull=true, DataFormatString="MM/yyyy", HtmlEncode=true)]
    public virtual DateTime? ExpirationDate { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=14, ShortName="Updated")]
    [DataType(DataType.DateTime)]
    [DisplayFormat(ConvertEmptyStringToNull=true, DataFormatString="MM/dd/yyyy HH:mm:ss", HtmlEncode=true)]
    public virtual DateTime? UpdateDate { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=15, ShortName="Updated By")]
    public virtual string UpdatedBy { get; set; }
}

I’ve tried this from an empty web template.

Please upload a minimal test repro project on GitHub that repro’s the issue with the latest v5.8 dependencies.

What version of VS / .NET framework did you use?

I didn’t, I tested with the web .NET Core project template I linked above, you never said anything about .NET Framework.

I’ve started again with the web-netfx .NET v4.6.1 Framework Project, e.g:

$ x new web-netfx AttributesTest

Same result:

public partial class PhysicalCount
{
    [Display(AutoGenerateFilter=true, Order=1, ShortName="Id", AutoGenerateField=false)]
    [AutoIncrement]
    public virtual int Id { get; set; }

    [Display(AutoGenerateFilter=true, Order=1, ShortName="ItemNumber", AutoGenerateField=false)]
    public virtual string ItemNumber { get; set; }

    [Display(AutoGenerateFilter=true, Order=2, ShortName="WarehouseCode", AutoGenerateField=false)]
    public virtual string WarehouseCode { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=3, ShortName="Qty")]
    public virtual int? QtyOnHand { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=4, ShortName="Lot Serial")]
    public virtual string LotSerial { get; set; }

    [Display(AutoGenerateFilter=true, Order=5, ShortName="LocationCode", AutoGenerateField=false)]
    public virtual string LocationCode { get; set; }

    [Display(AutoGenerateFilter=true, Order=6, ShortName="Device ID", AutoGenerateField=false)]
    public virtual string DeviceID { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=7, ShortName="Counted")]
    [DataType(DataType.DateTime)]
    [DisplayFormat(ConvertEmptyStringToNull=true, DataFormatString="MM/dd/yyyy HH:mm:ss", HtmlEncode=true)]
    public virtual DateTime CountDate { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=8, ShortName="Counted By")]
    public virtual string DeviceUser { get; set; }

    [Display(Order=9, ShortName="BatchKey", AutoGenerateField=false)]
    public virtual int? BatchKey { get; set; }

    [Display(AutoGenerateField=true, Order=-1, ShortName="Item")]
    [Association("Item.ItemID", "ItemKey", "ItemKey")]
    public virtual int ItemKey { get; set; }

    [Display(Order=-1, ShortName="Whse", AutoGenerateField=false)]
    public virtual int WhseKey { get; set; }

    [Display(AutoGenerateField=true, Order=-1, ShortName="Bin ID")]
    [Association("WarehouseBin.WhseBinID", "WhseBinKey", "WhseBinKey")]
    public virtual int WhseBinKey { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=4, ShortName="Expiration Date")]
    [DataType(DataType.DateTime)]
    [DisplayFormat(ConvertEmptyStringToNull=true, DataFormatString="MM/yyyy", HtmlEncode=true)]
    public virtual DateTime? ExpirationDate { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=14, ShortName="Updated")]
    [DataType(DataType.DateTime)]
    [DisplayFormat(ConvertEmptyStringToNull=true, DataFormatString="MM/dd/yyyy HH:mm:ss", HtmlEncode=true)]
    public virtual DateTime? UpdateDate { get; set; }

    [Display(AutoGenerateField=true, AutoGenerateFilter=true, Order=15, ShortName="Updated By")]
    public virtual string UpdatedBy { get; set; }
}

Make sure your project is definitely referencing the latest v5.8 dependencies, if it’s still an issue upload a minimal reproducible example on GitHub I can run locally to repro the issue.

I am very sorry for apparently wasting you time. I don’t know what was causing it but changing the BaseUrl to my production server seems to have fixed the problem. I will look further into it and post back here if I find anything but for now we can put this to bed.

1 Like