Tres - Step 4
Dependencies
As with Dos, we need reference to Nancy.Session.RavenDB and MiniGuid, and we also are going to need a package
called TaskBuilder.fs. All of these are covered by the packages we already reference in paket.dependencies, so we
just need to add these three packages to paket.references, then run paket install.
Boostrapper Updates
We need to add the Certificate and Password properties to our DataConfig record, so that we can use them to
configure our RavenDB connection. It becomes:
1: 2: 3: 4: 5: 6: |
|
Then, we'll convert our bootstrapper changes to F#. The bootstrapper is at the top of App.fs. We'll need to add some
open statements...
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: |
|
This is F#'s version of lazy initialization. There are a lot more parentheses here, as we're creating objects and then
calling into their properties or methods. That's just a feature of how F# works. In C#,
new DocumentStore().Initialize() will work; in F#, though, we have to set off the creation of the document store like
(new DocumentStore ()).Initialize (). (The space before the () is optional, and these extra parentheses are
required whether it's there or not.)
Now, we can chage ConfigureApplicationContainer and bring across ApplicationStartup.
1: 2: 3: 4: 5: 6: 7: 8: |
|
These are the same chages, just translated to F#.
Testing
As with Dos, we need to bring in the session extension method. Add open Nancy.Session.Persistable to the group of
open statements. C# only lets you define extension methods; however, F# allows you to define properties as well, so
PersistableSession is implemented as a property on Nancy's Request object. Then, we translate the function:
1: 2: 3: 4: 5: 6: 7: |
|
Since F# is designed to use Options to represent a value that may or may not be present (rather than null checks),
but Nancy's sessions are designed to return null if a value isn't found, this is a bit more work. We have to specify
the full type (Nullable<int>), as F# doesn't support the trailing question mark syntax. Then, we use the Option
module's ofNullable function to convert a nullable value into an option. Finally, we use an inline function, which
behaves the same way as a match statement on the value it receives via the pipe operator.
As with Uno and Dos, if you run the site, you should be able to refresh and see the counter increase.
Data Seeding
The bulk of this process is simply bringing over the HomeModule.Seed method from Dos. However, before we take a
look at it, we need to take a quick side trip to discuss a concept we've seen in Cinco but have not explained yet.
Computation Expressions
In F#, a computation expression (CE) is an expression that can have one or more steps that produce a result. For each
type of result, there is a different type of CE. For example, there is a seq CE that generates a sequence (F#'s term
for IEnumerable<T>). Within a CE, you will find regular F# keywords such as let, do, and match; you will also
likely find a return keyword (which we don't normally use, because a function's last value is its implied return
value). You will also see keywords followed by an exclamation point - let!, do!, match!, and return!; these
keywords will have special meaning, and will directly affect whatever computation is being determined.
The seq CE also has a yield keyword, that acts like yield return does in C#; the yield! keyword yields each of
the items of an existing sequence. Below is an example seq CE, which contains the parts of a fake US phone number.
1: 2: 3: 4: 5: |
|
We could combine these using let phone = x |> Seq.reduce (+).
The task CE
F# provides an async CE that is used to define a workflow that can execute asynchronous processes together with others
to produce a result. However, F#'s Async behaves a bit differently than the .NET Task and Task<T> types. F#'s
Async module does have functions like Async.AwaitTask that bring tasks into the F# async world. But, if we were to
write an await function, it would look something like:
1:
|
|
This makes something like let x = await (SomethingReturningATask()) or let x = await <| SomethingReturningATask().
However, that code doesn't flow very well; we either have to wrap the function/method calls in parentheses, or use
pipeline operators to send it to await. Also, this only works for Task<T>; we have to write a different one to
handle the non-generic Task.
Enter the task CE, provided by TaskBuilder.fs. It became popular as part of the Giraffe project, as Giraffe's
sitting atop ASP.NET Core required it to deal with tasks. Within a task CE, let! awaits a generic task, do!
awaits a non-generic task, match! awaits a generic task, then pattern-matches on the result, and return! awaits a
generic task and returns the result. return returns a regular value as the CE's result. The type of the task CE is
exactly what the rest of the .NET environment expects.
Take a look at the seed function to see
the task CE in action. open FSharp.Control.Tasks.V2.ContextInsensitive brings it into scope, and these tasks will
be run with .ConfigureAwait(false); this keeps tasks from deadlocking from waiting on the same execution context.
One final note - the :> obj at the bottom of the seed function makes the return type Task<obj> instead of
Task<string>, which is the required signature for NancyModule's Get method.
But Wait, There's More!
Go ahead and run it at this point, go to http://localhost:5000/seed, and compare the RavenDB documents for posts or
pages against the ones created for Dos. You'll notice that the content types (our IArticleContent fields) do not
have the ContentType and Text properties! For some reason, this is serialized differently if it's part of an F#
record type. (This may be an edge-case bug; if I can isolate the behavior, I'll submit an issue.) However, this gives
us a chance for an early look at writing our own custom JsonConverters. In step 3 Quatro, we added FSharpLu's
compact DU converter to RavenDB's configuration; this time, we'll write our own.
Just below the definition of MarkdownArticleContent, we'll create IArticleContentConverter, which will extend
JsonConverter<IArticleContent>. Generic converters need to implement two methods, WriteJson and ReadJson. Writing
is the easiest; and, we'll use the ContentType property to write a very succinct JSON object in of the form
{ "[Html|Markdown]" : [text] }. Here's the declaration, up through WriteJson.
1: 2: 3: 4: 5: 6: 7: 8: |
|
Each Write* call in Json.NET writes a token; these tokens describe the shape of the JSON that will eventually be
serialized. Since we're intercepting a single property, but writing an object, we write the start object token. Then,
we use ContentType for the property name, and Text for the value. We also need to write an end object token.
Reading it back is a bit different:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: |
|
When ReadJson is called, the starting object token has already been read. We read the tokens back in the order in
which we wrote them, so as we read through the JsonReader, we'll encounter our property name first, then the value
token. (We also need one more read to advance the reader past the end object token.) Once we have our property values,
the ContentType tells us what type of implementation to construct, and we can use the Text setter on the
IArticleContent interface to put the text in the object.
A bit of encouragement may be good here - I learned about what I've explained in this section when I encountered this problem for this project, and what you see above is the second version of it. I had written simple transformation
JsonConverters before, and the others we'll write will be like that. To me, this has been an illustration that no language is immune from the occasional odd behavior; but, if we apply what we already know, and do a bit of documentation diving, we'll often find an elegant solution. We might even no longer classify the behavior we encountered as odd!
We do need to revisit our RavenDB connection, though, as we need to actually plug our converter into the document store.
Here's the updated definition of _store from App.fs:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: |
|
At this point, use RavenDB studio to delete the existing documents, re-run the application, and re-seed the database.
You should now see ContentType and Text fields under the page/post's Text and Revision properties.
Conclusion
We did another C# to F# translation. We also learned about computation expressions in general, the task CE
specifically, and how to write a non-trivial JSON converter. Nice job - now, on to Quatro!
type Categories_ByWebLogIdAndSlug =
inherit AbstractJavaScriptIndexCreationTask
new : unit -> Categories_ByWebLogIdAndSlug
--------------------
new : unit -> Categories_ByWebLogIdAndSlug
type AbstractJavaScriptIndexCreationTask =
inherit AbstractIndexCreationTask
member CreateIndexDefinition : unit -> IndexDefinition
member Fields : Dictionary<string, IndexFieldOptions> with get, set
member IsMapReduce : bool
member Maps : HashSet<string> with get, set
--------------------
AbstractJavaScriptIndexCreationTask() : AbstractJavaScriptIndexCreationTask
type HashSet<'T> =
new : unit -> HashSet<'T> + 3 overloads
member Add : item:'T -> bool
member Clear : unit -> unit
member Comparer : IEqualityComparer<'T>
member Contains : item:'T -> bool
member CopyTo : array:'T[] -> unit + 2 overloads
member Count : int
member ExceptWith : other:IEnumerable<'T> -> unit
member GetEnumerator : unit -> Enumerator<'T>
member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
...
nested type Enumerator
--------------------
HashSet() : HashSet<'T>
HashSet(comparer: IEqualityComparer<'T>) : HashSet<'T>
HashSet(collection: IEnumerable<'T>) : HashSet<'T>
HashSet(collection: IEnumerable<'T>, comparer: IEqualityComparer<'T>) : HashSet<'T>
val string : value:'T -> string
--------------------
type string = System.String
type AutoOpenAttribute =
inherit Attribute
new : unit -> AutoOpenAttribute
new : path:string -> AutoOpenAttribute
member Path : string
--------------------
new : unit -> AutoOpenAttribute
new : path:string -> AutoOpenAttribute
type RequireQualifiedAccessAttribute =
inherit Attribute
new : unit -> RequireQualifiedAccessAttribute
--------------------
new : unit -> RequireQualifiedAccessAttribute
type LiteralAttribute =
inherit Attribute
new : unit -> LiteralAttribute
--------------------
new : unit -> LiteralAttribute
interface
abstract member Generate : unit -> string
abstract member ContentType : string
abstract member Text : string
abstract member Text : string with set
end
from Tres.Domain
type HtmlArticleContent =
interface IArticleContent
new : unit -> HtmlArticleContent
override ToString : unit -> string
--------------------
new : unit -> HtmlArticleContent
type MarkdownArticleContent =
interface IArticleContent
new : unit -> MarkdownArticleContent
override ToString : unit -> string
--------------------
new : unit -> MarkdownArticleContent
type JsonIgnoreAttribute =
inherit Attribute
new : unit -> JsonIgnoreAttribute
--------------------
JsonIgnoreAttribute() : JsonIgnoreAttribute
from Tres
type TresBootstrapper =
inherit DefaultNancyBootstrapper
new : unit -> TresBootstrapper
override ApplicationStartup : container:TinyIoCContainer * pipelines:IPipelines -> unit
override ConfigureApplicationContainer : container:TinyIoCContainer -> unit
--------------------
new : unit -> TresBootstrapper
type DefaultNancyBootstrapper =
inherit NancyBootstrapperWithRequestContainerBase<TinyIoCContainer>
new : unit -> DefaultNancyBootstrapper
member GetEnvironment : unit -> INancyEnvironment
static val DefaultAutoRegisterIgnoredAssemblies : IEnumerable<Func<Assembly, bool>>
--------------------
DefaultNancyBootstrapper() : DefaultNancyBootstrapper
static member AppendAllLines : path:string * contents:IEnumerable<string> -> unit + 1 overload
static member AppendAllText : path:string * contents:string -> unit + 1 overload
static member AppendText : path:string -> StreamWriter
static member Copy : sourceFileName:string * destFileName:string -> unit + 1 overload
static member Create : path:string -> FileStream + 3 overloads
static member CreateText : path:string -> StreamWriter
static member Decrypt : path:string -> unit
static member Delete : path:string -> unit
static member Encrypt : path:string -> unit
static member Exists : path:string -> bool
...
File.ReadAllText(path: string, encoding: System.Text.Encoding) : string
static val True : string
static val False : string
static val Null : string
static val Undefined : string
static val PositiveInfinity : string
static val NegativeInfinity : string
static val NaN : string
static member DefaultSettings : Func<JsonSerializerSettings> with get, set
static member DeserializeAnonymousType<'T> : value:string * anonymousTypeObject:'T -> 'T + 1 overload
static member DeserializeObject : value:string -> obj + 7 overloads
...
JsonConvert.DeserializeObject(value: string) : obj
JsonConvert.DeserializeObject<'T>(value: string, settings: JsonSerializerSettings) : 'T
JsonConvert.DeserializeObject<'T>(value: string, [<System.ParamArray>] converters: JsonConverter []) : 'T
JsonConvert.DeserializeObject(value: string, type: System.Type) : obj
JsonConvert.DeserializeObject(value: string, settings: JsonSerializerSettings) : obj
JsonConvert.DeserializeObject(value: string, type: System.Type, settings: JsonSerializerSettings) : obj
JsonConvert.DeserializeObject(value: string, type: System.Type, [<System.ParamArray>] converters: JsonConverter []) : obj
{Url: string;
Database: string;
Certificate: string;
Password: string;}
member Urls : string []
type DocumentStore =
inherit DocumentStoreBase
new : unit -> DocumentStore
member AggressivelyCacheFor : cacheDuration:TimeSpan * ?database:string -> IDisposable + 1 overload
member BulkInsert : ?database:string * ?token:CancellationToken -> BulkInsertOperation
member Changes : ?database:string -> IDatabaseChanges + 1 overload
member DisableAggressiveCaching : ?database:string -> IDisposable
member Dispose : unit -> unit
member GetLastDatabaseChangesStateException : ?database:string * ?nodeTag:string -> Exception
member GetRequestExecutor : ?database:string -> RequestExecutor
member Identifier : string with get, set
member Initialize : unit -> IDocumentStore
...
--------------------
DocumentStore() : DocumentStore
type X509Certificate2 =
inherit X509Certificate
new : unit -> X509Certificate2 + 12 overloads
member Archived : bool with get, set
member Extensions : X509ExtensionCollection
member FriendlyName : string with get, set
member GetNameInfo : nameType:X509NameType * forIssuer:bool -> string
member HasPrivateKey : bool
member Import : rawData:byte[] -> unit + 5 overloads
member IssuerName : X500DistinguishedName
member NotAfter : DateTime
member NotBefore : DateTime
...
--------------------
X509Certificate2() : X509Certificate2
(+0 other overloads)
X509Certificate2(rawData: byte []) : X509Certificate2
(+0 other overloads)
X509Certificate2(fileName: string) : X509Certificate2
(+0 other overloads)
X509Certificate2(handle: nativeint) : X509Certificate2
(+0 other overloads)
X509Certificate2(certificate: X509Certificate) : X509Certificate2
(+0 other overloads)
X509Certificate2(rawData: byte [], password: string) : X509Certificate2
(+0 other overloads)
X509Certificate2(rawData: byte [], password: System.Security.SecureString) : X509Certificate2
(+0 other overloads)
X509Certificate2(fileName: string, password: string) : X509Certificate2
(+0 other overloads)
X509Certificate2(fileName: string, password: System.Security.SecureString) : X509Certificate2
(+0 other overloads)
X509Certificate2(rawData: byte [], password: string, keyStorageFlags: X509KeyStorageFlags) : X509Certificate2
(+0 other overloads)
(+0 other overloads)
TinyIoc.TinyIoCContainer.Register<'RegisterType (requires reference type)>() : TinyIoc.TinyIoCContainer.RegisterOptions
(+0 other overloads)
TinyIoc.TinyIoCContainer.Register<'RegisterType (requires reference type)>(factory: System.Func<TinyIoc.TinyIoCContainer,TinyIoc.NamedParameterOverloads,'RegisterType>) : TinyIoc.TinyIoCContainer.RegisterOptions
(+0 other overloads)
TinyIoc.TinyIoCContainer.Register<'RegisterType,'RegisterImplementation (requires reference type and reference type and 'RegisterImplementation :> 'RegisterType)>(instance: 'RegisterImplementation) : TinyIoc.TinyIoCContainer.RegisterOptions
(+0 other overloads)
TinyIoc.TinyIoCContainer.Register<'RegisterType (requires reference type)>(instance: 'RegisterType) : TinyIoc.TinyIoCContainer.RegisterOptions
(+0 other overloads)
TinyIoc.TinyIoCContainer.Register<'RegisterType,'RegisterImplementation (requires reference type and reference type and 'RegisterImplementation :> 'RegisterType)>(name: string) : TinyIoc.TinyIoCContainer.RegisterOptions
(+0 other overloads)
TinyIoc.TinyIoCContainer.Register<'RegisterType (requires reference type)>(name: string) : TinyIoc.TinyIoCContainer.RegisterOptions
(+0 other overloads)
TinyIoc.TinyIoCContainer.Register(registerType: System.Type) : TinyIoc.TinyIoCContainer.RegisterOptions
(+0 other overloads)
TinyIoc.TinyIoCContainer.Register<'RegisterType (requires reference type)>(factory: System.Func<TinyIoc.TinyIoCContainer,TinyIoc.NamedParameterOverloads,'RegisterType>, name: string) : TinyIoc.TinyIoCContainer.RegisterOptions
(+0 other overloads)
TinyIoc.TinyIoCContainer.Register<'RegisterType,'RegisterImplementation (requires reference type and reference type and 'RegisterImplementation :> 'RegisterType)>(instance: 'RegisterImplementation, name: string) : TinyIoc.TinyIoCContainer.RegisterOptions
(+0 other overloads)
inherit IDisposalNotification
inherit IDisposable
member AggressivelyCache : ?database:string -> IDisposable
member AggressivelyCacheFor : cacheDuration:TimeSpan * ?database:string -> IDisposable + 1 overload
member BulkInsert : ?database:string * ?token:CancellationToken -> BulkInsertOperation
member Certificate : X509Certificate2
member Changes : ?database:string -> IDatabaseChanges + 1 overload
member Conventions : DocumentConventions
member Database : string with get, set
member DisableAggressiveCaching : ?database:string -> IDisposable
member ExecuteIndex : task:AbstractIndexCreationTask * ?database:string -> unit
member ExecuteIndexAsync : task:AbstractIndexCreationTask * ?database:string * ?token:CancellationToken -> Task
...
static member CreateIndexes : assemblyToScan:Assembly * store:IDocumentStore * ?conventions:DocumentConventions * ?database:string -> unit + 1 overload
static member CreateIndexesAsync : assemblyToScan:Assembly * store:IDocumentStore * ?conventions:DocumentConventions * ?database:string * ?token:CancellationToken -> Task + 1 overload
IndexCreation.CreateIndexes(assemblyToScan: System.Reflection.Assembly, store: IDocumentStore,?conventions: Conventions.DocumentConventions,?database: string) : unit
type PersistableSessions =
new : cfg:IPersistableSessionConfiguration -> PersistableSessions
member Load : request:Request -> IPersistableSession
member Save : session:IPersistableSession -> response:Response -> unit
static member Enable : pipelines:IPipelines * cfg:IPersistableSessionConfiguration -> unit
static member private LoadSession : ctx:NancyContext -> provider:PersistableSessions -> Response
static member private SaveSession : ctx:NancyContext -> provider:PersistableSessions -> unit
--------------------
new : cfg:IPersistableSessionConfiguration -> PersistableSessions
type RavenDBSessionConfiguration =
inherit BasePersistableSessionConfiguration
new : unit -> RavenDBSessionConfiguration
new : store:IDocumentStore -> RavenDBSessionConfiguration
new : store:IDocumentStore * cryptoConfig:CryptographyConfiguration -> RavenDBSessionConfiguration
member Collection : string
member Database : string
member DocumentStore : IDocumentStore
override Store : IPersistableSessionStore
member Collection : string with set
member Database : string with set
...
--------------------
new : unit -> RavenDBSessionConfiguration
new : store:IDocumentStore -> RavenDBSessionConfiguration
new : store:IDocumentStore * cryptoConfig:Cryptography.CryptographyConfiguration -> RavenDBSessionConfiguration
type HomeModule =
inherit NancyModule
new : unit -> HomeModule
--------------------
new : unit -> HomeModule
type NancyModule =
member After : AfterPipeline with get, set
member Before : BeforePipeline with get, set
member Context : NancyContext with get, set
member Delete : path:string * action:Func<obj, obj> * ?condition:Func<NancyContext, bool> * ?name:string -> unit + 5 overloads
member Get : path:string * action:Func<obj, obj> * ?condition:Func<NancyContext, bool> * ?name:string -> unit + 5 overloads
member Head : path:string * action:Func<obj, obj> * ?condition:Func<NancyContext, bool> * ?name:string -> unit + 5 overloads
member ModelBinderLocator : IModelBinderLocator with get, set
member ModelValidationResult : ModelValidationResult with get, set
member ModulePath : string with get, set
member Negotiate : Negotiator
...
--------------------
NancyModule() : NancyModule
NancyModule(modulePath: string) : NancyModule
NancyModule.Get(path: string, action: Func<obj,Threading.CancellationToken,Threading.Tasks.Task<obj>>,?condition: Func<NancyContext,bool>,?name: string) : unit
NancyModule.Get<'T>(path: string, action: Func<obj,Threading.Tasks.Task<'T>>,?condition: Func<NancyContext,bool>,?name: string) : unit
NancyModule.Get(path: string, action: Func<obj,Threading.Tasks.Task<obj>>,?condition: Func<NancyContext,bool>,?name: string) : unit
NancyModule.Get<'T>(path: string, action: Func<obj,'T>,?condition: Func<NancyContext,bool>,?name: string) : unit
NancyModule.Get(path: string, action: Func<obj,obj>,?condition: Func<NancyContext,bool>,?name: string) : unit
type Nullable =
static member Compare<'T> : n1:Nullable<'T> * n2:Nullable<'T> -> int
static member Equals<'T> : n1:Nullable<'T> * n2:Nullable<'T> -> bool
static member GetUnderlyingType : nullableType:Type -> Type
--------------------
type Nullable<'T (requires default constructor and value type and 'T :> ValueType)> =
struct
new : value:'T -> Nullable<'T>
member Equals : other:obj -> bool
member GetHashCode : unit -> int
member GetValueOrDefault : unit -> 'T + 1 overload
member HasValue : bool
member ToString : unit -> string
member Value : 'T
end
--------------------
Nullable ()
Nullable(value: 'T) : Nullable<'T>
val int : value:'T -> int (requires member op_Explicit)
--------------------
type int = int32
--------------------
type int<'Measure> = int
from Microsoft.FSharp.Core
val seq : sequence:seq<'T> -> seq<'T>
--------------------
type seq<'T> = Collections.Generic.IEnumerable<'T>
type Async =
static member AsBeginEnd : computation:('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit)
static member AwaitEvent : event:IEvent<'Del,'T> * ?cancelAction:(unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate)
static member AwaitIAsyncResult : iar:IAsyncResult * ?millisecondsTimeout:int -> Async<bool>
static member AwaitTask : task:Task -> Async<unit>
static member AwaitTask : task:Task<'T> -> Async<'T>
static member AwaitWaitHandle : waitHandle:WaitHandle * ?millisecondsTimeout:int -> Async<bool>
static member CancelDefaultToken : unit -> unit
static member Catch : computation:Async<'T> -> Async<Choice<'T,exn>>
static member Choice : computations:seq<Async<'T option>> -> Async<'T option>
static member FromBeginEnd : beginAction:(AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
...
--------------------
type Async<'T> =
static member Async.AwaitTask : task:Threading.Tasks.Task<'T> -> Async<'T>
type IArticleContentConverter =
inherit JsonConverter<IArticleContent>
new : unit -> IArticleContentConverter
override ReadJson : r:JsonReader * Type * IArticleContent * bool * JsonSerializer -> IArticleContent
override WriteJson : w:JsonWriter * v:IArticleContent * JsonSerializer -> unit
--------------------
new : unit -> IArticleContentConverter
type JsonConverter =
member CanConvert : objectType:Type -> bool
member CanRead : bool
member CanWrite : bool
member ReadJson : reader:JsonReader * objectType:Type * existingValue:obj * serializer:JsonSerializer -> obj
member WriteJson : writer:JsonWriter * value:obj * serializer:JsonSerializer -> unit
--------------------
type JsonConverter<'T> =
inherit JsonConverter
member CanConvert : objectType:Type -> bool
member ReadJson : reader:JsonReader * objectType:Type * existingValue:obj * serializer:JsonSerializer -> obj + 1 overload
member WriteJson : writer:JsonWriter * value:obj * serializer:JsonSerializer -> unit + 1 overload
--------------------
type JsonConverterAttribute =
inherit Attribute
new : converterType:Type -> JsonConverterAttribute + 1 overload
member ConverterParameters : obj[]
member ConverterType : Type
--------------------
JsonConverter() : JsonConverter
--------------------
JsonConverter() : JsonConverter<'T>
--------------------
JsonConverterAttribute(converterType: Type) : JsonConverterAttribute
JsonConverterAttribute(converterType: Type, [<ParamArray>] converterParameters: obj []) : JsonConverterAttribute
member AutoCompleteOnClose : bool with get, set
member Close : unit -> unit
member CloseAsync : ?cancellationToken:CancellationToken -> Task
member CloseOutput : bool with get, set
member Culture : CultureInfo with get, set
member DateFormatHandling : DateFormatHandling with get, set
member DateFormatString : string with get, set
member DateTimeZoneHandling : DateTimeZoneHandling with get, set
member FloatFormatHandling : FloatFormatHandling with get, set
member Flush : unit -> unit
...
type JsonSerializer =
new : unit -> JsonSerializer
member Binder : SerializationBinder with get, set
member CheckAdditionalContent : bool with get, set
member ConstructorHandling : ConstructorHandling with get, set
member Context : StreamingContext with get, set
member ContractResolver : IContractResolver with get, set
member Converters : JsonConverterCollection
member Culture : CultureInfo with get, set
member DateFormatHandling : DateFormatHandling with get, set
member DateFormatString : string with get, set
...
--------------------
JsonSerializer() : JsonSerializer
JsonWriter.WritePropertyName(name: string, escape: bool) : unit
(+0 other overloads)
JsonWriter.WriteValue(value: Uri) : unit
(+0 other overloads)
JsonWriter.WriteValue(value: byte []) : unit
(+0 other overloads)
JsonWriter.WriteValue(value: Nullable<TimeSpan>) : unit
(+0 other overloads)
JsonWriter.WriteValue(value: Nullable<Guid>) : unit
(+0 other overloads)
JsonWriter.WriteValue(value: Nullable<DateTimeOffset>) : unit
(+0 other overloads)
JsonWriter.WriteValue(value: Nullable<DateTime>) : unit
(+0 other overloads)
JsonWriter.WriteValue(value: Nullable<decimal>) : unit
(+0 other overloads)
JsonWriter.WriteValue(value: Nullable<sbyte>) : unit
(+0 other overloads)
JsonWriter.WriteValue(value: Nullable<byte>) : unit
(+0 other overloads)
member Close : unit -> unit
member CloseInput : bool with get, set
member Culture : CultureInfo with get, set
member DateFormatString : string with get, set
member DateParseHandling : DateParseHandling with get, set
member DateTimeZoneHandling : DateTimeZoneHandling with get, set
member Depth : int
member FloatParseHandling : FloatParseHandling with get, set
member MaxDepth : Nullable<int> with get, set
member Path : string
...
from Tres
File.ReadAllText(path: string, encoding: Text.Encoding) : string
JsonConvert.DeserializeObject(value: string) : obj
JsonConvert.DeserializeObject<'T>(value: string, settings: JsonSerializerSettings) : 'T
JsonConvert.DeserializeObject<'T>(value: string, [<ParamArray>] converters: JsonConverter []) : 'T
JsonConvert.DeserializeObject(value: string, type: Type) : obj
JsonConvert.DeserializeObject(value: string, settings: JsonSerializerSettings) : obj
JsonConvert.DeserializeObject(value: string, type: Type, settings: JsonSerializerSettings) : obj
JsonConvert.DeserializeObject(value: string, type: Type, [<ParamArray>] converters: JsonConverter []) : obj
type X509Certificate2 =
inherit X509Certificate
new : unit -> X509Certificate2 + 12 overloads
member Archived : bool with get, set
member Extensions : X509ExtensionCollection
member FriendlyName : string with get, set
member GetNameInfo : nameType:X509NameType * forIssuer:bool -> string
member HasPrivateKey : bool
member Import : rawData:byte[] -> unit + 5 overloads
member IssuerName : X500DistinguishedName
member NotAfter : DateTime
member NotBefore : DateTime
...
--------------------
X509Certificate2() : X509Certificate2
(+0 other overloads)
X509Certificate2(rawData: byte []) : X509Certificate2
(+0 other overloads)
X509Certificate2(fileName: string) : X509Certificate2
(+0 other overloads)
X509Certificate2(handle: nativeint) : X509Certificate2
(+0 other overloads)
X509Certificate2(certificate: X509Certificate) : X509Certificate2
(+0 other overloads)
X509Certificate2(rawData: byte [], password: string) : X509Certificate2
(+0 other overloads)
X509Certificate2(rawData: byte [], password: Security.SecureString) : X509Certificate2
(+0 other overloads)
X509Certificate2(fileName: string, password: string) : X509Certificate2
(+0 other overloads)
X509Certificate2(fileName: string, password: Security.SecureString) : X509Certificate2
(+0 other overloads)
X509Certificate2(rawData: byte [], password: string, keyStorageFlags: X509KeyStorageFlags) : X509Certificate2
(+0 other overloads)