fsprojects / FSharp.Azure.Storage

F# API for using Microsoft Azure Table Storage service
MIT License
75 stars 16 forks source link

Type must be either an ITableEntity or an F# record type #8

Closed jackfoxy closed 9 years ago

jackfoxy commented 9 years ago

This may be as simple as a binding redirect issue, but not sure how to resolve it. I think both the successful and unsuccessful cases load the same mscorlib.dll:

Occurring in a Class library (.NET 4.6, F# 4.0) with public function on the following statement:

DigitallyCreated.FSharp.Azure.TableStorage.Query.all<QueryInternal>

QueryInternal defined thus:

type QueryInternal =
    { 
    [<PartitionKey>]QueryHash : string
    [<RowKey>] RowKey : string
    IsActive : bool
    Name : string
    Query : string
    ConnectionName : string
    CreateTime : DateTime
    }

I tried making QueryInternal public, but to no effect.

Console app ().NET 4.6, F# 4.0) calls this function and succeeds.

Class test library (.NET 4.6, F# 4.0, xUnit 1.9.2) calls this function and fails:

System.Exception was unhandled by user code Message: An exception of type 'System.Exception' occurred in mscorlib.dll but was not handled in user code Additional information: Type QueryInternal must be either an ITableEntity or an F# record type

My working theory is this is an incompatability with xUnit 1.9.2.

daniel-chambers commented 9 years ago

Ah, F# 4 and .NET 4.6.

I'm planning on building a new dev image on Windows 10 and VS2015 probably this week once Windows 10 lands. Once it's up and going, I'll try to reproduce this using all the new bits.

jackfoxy commented 9 years ago

Here is the call stack within TableStorage in the failing case:

DigitallyCreated.FSharp.Azure.dll!DigitallyCreated.FSharp.Azure.TableStorage.-cctor@159-4.Invoke(Microsoft.FSharp.Core.Unit unitVar) Line 174 DigitallyCreated.FSharp.Azure.dll!DigitallyCreated.FSharp.Azure.TableStorage.EntityQuery.get_Zero() Line 194 DigitallyCreated.FSharp.Azure.dll!DigitallyCreated.FSharp.Azure.TableStorage.Query.all() Line 335

it is failing from the match pattern t when typeof<ITableEntity>.IsAssignableFrom t

In the succeeding case it is matching the pattern t when isRecordType t in the following match statement

match typeof<'T> with
| t when typeof<ITableEntity>.IsAssignableFrom t -> 
    t.GetProperties()
    |> Seq.choose getTableEntityProperty
    |> Set.ofSeq
| t when isRecordType t -> 
    RecordTableEntityWrapper<'T>.RecordFields 
    |> Seq.map (fun p -> p.Name) 
    |> Set.ofSeq
| t -> failwithf "Type %s must be either an ITableEntity or an F# record type" t.Name

BTW, my colleague, Cameron Taggart, has a nice system called SourceLink, http://ctaggart.github.io/SourceLink/index.html, which makes debugging .NET OSS muck simpler. Making FSharp.Azure compatible would make it far simpler for people to identify issues.

jackfoxy commented 9 years ago

Closing. I don't know how Visual Studio ever emitted this stack trace for the error thrown. Finally discovered it was no longer emitting this stack trace. Not a problem.

daniel-chambers commented 9 years ago

Out of interest, what did the actual problem end up being?

jackfoxy commented 9 years ago

forgetting unit at the end of ToString, i.e. .ToString instead of .ToString()

jackfoxy commented 9 years ago

I've noticed the VS debugger leaves some Exceptin artifacts lying around. This may have been an instance of that