I am rather new to F# but I have a question about creating and reading custom configuration file. I know how it would look in c# so for example I have a simple config file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="customSection" type="Tool.Lib.Config, Tool.Lib" />
</configSections>
<communicationSection>
<responseTimeoutInMs value="900000" />
</communicationSection>
</configuration>
Basing on that in c# it is simple. I am creating model named Config with properties marked as ConfigurationProperty (witch relates to xml node name, in this case responseTimeoutInMs) something like:
[ConfigurationProperty("responseTimeoutInMs")]
public ResponseTimeoutConfigElement ResponseTimeoutInMs
{
get => (ResponseTimeoutConfigElement)base["responseTimeoutInMs"];
set => base["responseTimeoutInMs"] = value;
}
And of course value is set as ConfigurationElement so:
public class ResponseTimeoutConfigElement : ConfigurationElement
{
[ConfigurationProperty("value", IsRequired = true, IsKey = true, DefaultValue = 0)]
public int Value => (int)base["value"];
}
It is a nice mechanism, I can pin converters into it and create types I need while reading configuration.
I know i can read default config using ConfigurationManager and exe configuration map, but this is basic config reading using key and value.
So my question is, is there something similar in F# to this in C#?
I'm not sure if it's quite what you're after as you mention using a "custom configuration file", but in the past I've used the AppSettings Type Provider to get strongly typed access to app variables.
If that's not appropriate, there's also a more standard XML type provider that might help?
I find type providers really useful in avoiding having to write boilerplate code for simple access, and they're a really nice feature of F# development.
You can do pretty much the same thing in F# as in C#:
type ResponseTimeoutConfigElement() =
inherit ConfigurationElement()
[<ConfigurationProperty("value", IsRequired = true, IsKey = true, DefaultValue = 0)>]
member this.Value = base.["value"] :?> int
type Config() =
inherit ConfigurationSection()
[<ConfigurationProperty("responseTimeoutInMs")>]
member this.ResponseTimeInMs
with get() = base.["responseTimeoutInMs"] :?> ResponseTimeoutConfigElement
and set (value: ResponseTimeoutConfigElement) = base.["responseTimeoutInMs"] <- value
Related
In a C# class with a single constructor, I can add class summary XML documentation and constructor XML documentation:
///<summary>
///This class will solve all your problems
///</summary>
public class Awesome
{
/// <summary>
/// Initializes a new instance of the <see cref="Awesome"/> class.
/// </summary>
/// <param name="sauce">The secret sauce.</param>
public Awesome(string sauce)
{
//...implementation elided for security purposes
}
}
How do I do the same with the equivalent F# class such that the generated documentation is the same?
type Awesome(sauce: string) =
//...implementation elided for security purposes
CLARIFICATION: I'm aware that the standard XML documentation tags can be used in F#. My question is how to add them to the above snippet so that both the type and the constructor are documented.
I looked at the source of the open-source F# compiler and I think Dr_Asik is right - there is no way of documenting the implicit constructor with an XML comment. The node that represents the implicit constructor in the AST (See ImplicitCtor in ast.fs here) does not include a field for stroing the XML documentation (represented as PreXmlDoc type).
You can still document all public API - you'd have to use the method that Dr_Asik mentioned and mark the implicit constructor as private. I agree this is a bit ugly, but I think it is more convenient than not using implicit constructors:
type MyType private(a:int, u:unit) =
/// <summary>Creates MyType</summary>
/// <param name="a">Parameter A</param>
new(a:int) = MyType(a, ())
I added a dummy parameter u to the implicit constructor, so that it can be called from the public constructor. Anyway, I think this should be considered as a language bug and so I'd suggest reporting this to fsbugs at microsoft dot com.
As an aside, I think the XML documentation is mainly useful as a source of data for IntelliSense (which still needs documentation for the constructor, though) and I created some alternative F# tools that let you create tutorials and documentation by writing an F# script file with special comments using Markdown (there is a blog post about it) - so you may consider that as a useful addition to the standard XML tooling.
In exactly the same way as you do in C#: http://msdn.microsoft.com/en-us/library/dd233217.aspx
If you don't put any tags, F# assumes it is "summary":
/// This is the documentation
type MyType() = ....
... is equivalent to
/// <summary>This is the documentation</summary>
type MyType() = ...
If you want to document a constructor, you'll have to declare it explicitely. AFAIK there is no way to document the primary constructor.
/// [Type summary goes here]
type MyType(a : int) =
let m_a = a
/// [Parameterless constructor documentation here]
new() = MyType(0)
There is no way to document the implicit constructor with an XML comment inside an F# source file (.fs). One workaround is to declare the constructor explicitly (see Dr Asik's answer). Another is to put your XML comments into an F# Signature File (.fsi).
File.fs:
module File
type Awesome(sauce: string) =
member x.Sauce = sauce
File.fsi
module File
type Awesome =
class
/// Implicit constructor summary for the Awesome type
new : sauce:string -> Awesome
member Sauce : string
end
The XML documentation for this assembly will now contain the correct summary:
<member name="M:File.Awesome.#ctor(System.String)">
<summary>
Implicit constructor summary for the Awesome type
</summary>
</member>
This really is an annoying problem.
Another solution I ended up using is to not rely on a primary constructor:
/// Documentation type.
type Awesome =
val sauce : string
/// <summary>Documentation constructor.</summary>
/// <param name="sauce">Sauce. Lots of it.</param>
new (sauce) = { sauce = sauce }
More verbose, but no extra files or private constructors needed...
In my MVC application I have the ability to get the error message from a text file instead of using the default error message. This works perfectly on the Required attribute (both Serverside and Clientside).
I now need to do the same with the Compare attribute, but I can't figure out how to override the Compare attribute.
For reference, this is how I am doing it with the Required attribute (I would like similar code to this to work with the Compare attribute)...
Public Class RequiredFieldAttribute
Inherits ValidationAttribute
Implements IClientValidatable
Private innerAttribute As New RequiredAttribute()
Private errormessagecontrolid As String
Public Sub New(ErrorMessageControlID As String)
Me.errormessagecontrolid = ErrorMessageControlID
End Sub
Protected Overrides Function IsValid(value As Object, validationContext As ValidationContext) As ValidationResult
If Not innerAttribute.IsValid(value) Then
Return New ValidationResult(ErrorMsgs.Text(Me.errormessagecontrolid))
End If
Return ValidationResult.Success
End Function
Public Function GetClientValidationRules(metadata As ModelMetadata, context As ControllerContext) As IEnumerable(Of ModelClientValidationRule) Implements IClientValidatable.GetClientValidationRules
Dim result = New List(Of ModelClientValidationRule)
Dim rule = New ModelClientValidationRule() With {.ErrorMessage = ErrorMsgs.Text(Me.errormessagecontrolid), .ValidationType = "required"}
result.Add(rule)
Return result
End Function
End Class
Above, ErrorMsgs.Text is the function that retieves the message from the text file. Against my model I then apply something like this...
<RequiredField("AccountDetailsPostcodeError")>
Public Property PostCode As String
The system then looks in the Text file for an entry called AccountDetailsPostcodeError.
How can I achieve the same with the Compare attribute. At the moment I have a hard coded error message like this...
<Compare("WebPassword", ErrorMessage:="The password and confirmation do not match.")>
Public Property ConfirmWebPassword As String
Edit: The suggested fix below may work in C#, but won't work in VB.NET, hence my more complex requirement to override the Compare attribute. I just don't know how to correctly override it.
Why use a text file for your translations and messages, .NET has build in options for translations. You can use resources. The advantage of using resources is that resources are type safe, they are checked as compile time. Where your textfile can become corrupt / missing.
The following guide helps you with setting up resources in a Mvc project:
Step one
Edit the default assembly language:
(C#) Properties > Assembly information > Neutral Language
(VB) My Project > Assembly information > Neutral Language
Set this language to your default language. (For this example I use English (United States))
Step two
Add a resource file to your project. Call this file Resource.resx. Open this file. Change the Access Modifier to Public and start adding resource strings. For example:
Step three
Add for each other language you want to support another resource file but name them Resource.LANGUAGE.resx where LANGUAGE is replaced by the other culture name. For culture names you can check this url: http://msdn.microsoft.com/en-us/goglobal/bb896001.aspx
Then fill the new resource file with the localized strings. For example:
Step four
Then you can in your Models use the default localization support of the attributes:
For example:
VB:
Imports System.ComponentModel.DataAnnotations
Public Class UserModel
<Display(Name:="UserNameField", ResourceType:=GetType(My.Resources.Resource))>
<Required(AllowEmptyStrings:=False, ErrorMessageResourceName:="RequiredUsername", ErrorMessageResourceType:=GetType(My.Resources.Resource))>
Public Property UserName As String
<Display(Name:="PasswordField", ResourceType:=GetType(My.Resources.Resource))>
<MinLength(6, ErrorMessageResourceName:="PasswordLengthError", ErrorMessageResourceType:=GetType(My.Resources.Resource))>
<Compare("PasswordAgain", ErrorMessageResourceName:="CompareError", ErrorMessageResourceType:=GetType(My.Resources.Resource))>
<Required(AllowEmptyStrings:=False, ErrorMessageResourceName:="RequiredPassword", ErrorMessageResourceType:=GetType(My.Resources.Resource))>
Public Property Password As String
<Display(Name:="PasswordAgainField", ResourceType:=GetType(My.Resources.Resource))>
<Required(AllowEmptyStrings:=False, ErrorMessageResourceName:="RequiredPasswordAgain", ErrorMessageResourceType:=GetType(My.Resources.Resource))>
Public Property PasswordAgain As String
End Class
C#
using System.ComponentModel.DataAnnotations;
public class UserModel
{
[Display(Name = "UserNameField", ResourceType = typeof(My.Resources.Resource))]
[Required(AllowEmptyStrings = False, ErrorMessageResourceName = "RequiredUsername", ErrorMessageResourceType = typeof(My.Resources.Resource))]
public string UserName;
[Display(Name = "PasswordField", ResourceType = typeof(My.Resources.Resource))]
[MinLength(6, ErrorMessageResourceName = "PasswordLengthError", ErrorMessageResourceType = typeof(My.Resources.Resource))]
[Compare("PasswordAgain", ErrorMessageResourceName = "CompareError", ErrorMessageResourceType = typeof(My.Resources.Resource))]
[Required(AllowEmptyStrings = False, ErrorMessageResourceName = "RequiredPassword", ErrorMessageResourceType = typeof(My.Resources.Resource))]
public string Password;
[Display(Name = "PasswordAgainField", ResourceType = typeof(My.Resources.Resource))]
[Required(AllowEmptyStrings = False, ErrorMessageResourceName = "RequiredPasswordAgain", ErrorMessageResourceType = typeof(My.Resources.Resource))]
public string PasswordAgain;
}
For localization the attribute needs to know the name of the static property and the type of the static class where to get the property from (as seen above).
Step five
Then in your view use the #Html.ValidationSummary() to get all the error messages, or use
VB #Html.ValidationMessageFor(Function(model) model.Property)
C# #Html.ValidationMessageFor(m => m.Property)
to get specific error messages.
For the display attribute you can use:
VB #Html.DisplayNameFor(Function(model) model.Property)
C# #Html.DisplayNameFor(m => m.Property)
Changing the language
And last but not least you can change the language of your app instead of your neutral language defined in step one by editing the Web.config and changing the globalization tag like so:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<globalization uiCulture="nl" />
</system.web>
</configuration>
If you want to change the language from code you should edit System.Threading.Thread.CurrentThread.CurrentUICulture for information about this I suggest google or another SO question.
Example project
For this question I quickly made an example project to provide an accurate answer. Project can be found here:
MvcVBTest.V1.zip
UPDATE
If you don't want to use Resources but a single text file you can use the same concept the resource framework uses. You need a class that has static properties you can reference.
For this purpose I did the following things:
I created a class called Resources (Resources.vb).
In this class I added a sub class called Resource
In the static constructor of this class I open resource.xml which I have mapped to an array of Resource
This array is then converted to an Dictionary(Of String, String)
I created an static get property for every item in the xml. And returned the right item from the Dictionary
I changed the ResourceType parameter in the UserModel class
And of course a little clean up. The old resources can be deleted and the globalization tag can be removed from the web.config.
Now all the text can be found in resource.xml as key value pairs. To add another line, add it to the XML and create a property for it in the Resource class.
Example project
For this update I updated my example project:
MvcVBTest.V2.zip
Why not use something like this?
<RequiredField(ErrorMessage=GetErrorMessage())>
Just create a static function that gets the error message for you. You can even take a parameter for your GetErrorMessage function so you can determine which message you'll want to return.
Updated below...
I recently started experimenting with ServiceStack in F#, so naturally I started with porting the Hello World sample:
open ServiceStack.ServiceHost
open ServiceStack.ServiceInterface
open ServiceStack.WebHost.Endpoints
[<CLIMutable; Route("/hello"); Route("/hello/{Name}")>]
type Hello = { Name : string }
[<CLIMutable>]
type HelloResponse = { Result : string }
type HelloService() =
inherit Service()
member x.Any(req:Hello) =
box { Result = sprintf "Hello, %s!" req.Name }
type HelloAppHost() =
inherit AppHostBase("Hello Web Services", typeof<HelloService>.Assembly)
override x.Configure container = ()
type Global() =
inherit System.Web.HttpApplication()
member x.Application_Start() =
let appHost = new HelloAppHost()
appHost.Init()
That works great. It's very concise, easy to work with, I love it. However, I noticed that the routes defined in the sample allow for the Name parameter to not be included. Of course, Hello, ! looks kind of lame as output. I could use String.IsNullOrEmpty, but it is idiomatic in F# to be explicit about things that are optional by using the Option type. So I modified my Hello type accordingly to see what would happen:
[<CLIMutable; Route("/hello"); Route("/hello/{Name}")>]
type Hello = { Name : string option }
As soon as I did this, the F# type system forced me to deal with the fact that Name might not have a value, so I changed HelloService to this to get everything to compile:
type HelloService() =
inherit Service()
member x.Any(req:Hello) =
box { Result =
match req.Name with
| Some name -> sprintf "Hello, %s!" name
| None -> "Hello!" }
This compiles, and runs perfectly when I don't supply a Name parameter. However, when I do supply a name...
KeyValueDataContractDeserializer: Error converting to type: Type
definitions should start with a '{', expecting serialized type
'FSharpOption`1', got string starting with: World
This wasn't a complete surprise of course, but it brings me to my question:
It would be trivial for me to write a function that can wrap an instance of type T into an instance of type FSharpOption<T>. Are there any hooks in ServiceStack that would let me provide such a function for use during deserialization? I looked, but I couldn't find any, and I'm hoping I was just looking in the wrong place.
This is more important for F# use than it might seem at first, because classes defined in F# are by default not allowed to be null. So the only (satisfying, non-hacky) way of having one class as an optional property of another class is with, you guessed it, the Option type.
Update:
I was able to sort-of get this working by making the following changes:
In the ServiceStack source, I made this type public:
ServiceStack.Text.Common.ParseFactoryDelegate
...and I also made this field public:
ServiceStack.Text.Jsv.JsvReader.ParseFnCache
With those two things public, I was able to write this code in F# to modify the ParseFnCache dictionary. I had to run this code prior to creating an instance of my AppHost - it didn't work if I ran it inside the AppHost's Configure method.
JsvReader.ParseFnCache.[typeof<Option<string>>] <-
ParseFactoryDelegate(fun () ->
ParseStringDelegate(fun s -> (if String.IsNullOrEmpty s then None else Some s) |> box))
This works for my original test case, but aside from the fact that I had to make brittle changes to the internals of ServiceStack, it sucks because I have to do it once for each type I want to be able to wrap in an Option<T>.
What would be better is if I could do this in a generic way. In C# terms, it would be awesome if I could provide to ServiceStack a Func<T, Option<T>> and ServiceStack would, when deserializing a property whose generic type definition matches that of the return type of my function, deserialize T and then pass the result into my function.
Something like that would be amazingly convenient, but I could live with the once-per-wrapped-type approach if it were actually part of ServiceStack and not my ugly hack that probably breaks something somewhere else.
So there are a couple of extensibility points in ServiceStack, on the framework level you can add your own Custom Request Binder this allows you to provide your own model binder that's used, e.g:
base.RequestBinders.Add(typeof(Hello), httpReq => {
var requestDto = ...;
return requestDto;
});
But then you would need to handle the model binding for the different Content-Types yourself, see CreateContentTypeRequest for how ServiceStack does it.
Then there are hooks at the JSON Serializer level, e.g:
JsConfig<Hello>.OnDeserializedFn = dto => newDto;
This lets you modify the instance of the type returned, but it still needs to be the same type but it looks like the F# option modifier changes the structural definition of the type?
But I'm open to adding any hooks that would make ServiceStack more palatable for F#.
What does the code look like to generically convert a normal Hello type to an F# Hello type with option?
The only thing I can think of is to replace the option type with your own type, one that has an implicit conversion from string to myOption, and anything else you need.
Not all that nice, but workable. Your type would probably also need to be serializable.
type myOption =
| None
| Some of string
static member public op_Implicit (s:string) = if s <> null then Some s else None
member public this.Value = match this with
| Some s -> s
| _ -> null
member this.Opt = match this with
| Some s -> Option.Some s
| None -> Option.None
Your record type would then be
[<CLIMutable>]
type Hello =
{ Name : myOption }
On the other hand, ServiceStack is open source, so maybe something could be done there.
I am using unity as my IoC container. I am trying to implement a type of IProviderRepository. The concrete implementation has a constructor that accepts a type of IRepository. When I remove the constructor parameter from the concrete implementation everything works fine. I am sure the container is wired correctly. When I try to create the concrete object with the constructor I receive the following error:
"The current build operation (build key Build Key[EMRGen.Infrastructure.Data.IRepository1[EMRGen.Model.Provider.Provider], null]) failed: The current type, EMRGen.Infrastructure.Data.IRepository1[EMRGen.Model.Provider.Provider], is an interface and cannot be constructed. Are you missing a type mapping? (Strategy type BuildPlanStrategy, index 3)".
Is it possible to achieve the above mention functionality with Unity? Namely have Unity infer a concrete type from the Interface and also inject the constructor of the concrete type with the appropriate concrete object based on constructor parameters. Below is sample of my types defined in Unity and a skeleton class listing for what I want to achieve. IProviderRepository is implemented by ProviderRepository which has a constructor that expects a type of IRepository.
<typeAlias alias="ProviderRepositoryInterface" type="EMRGen.Model.Provider.IProviderRepository, EMRGen.Model" />
<typeAlias alias="ProviderRepositoryConcrete" type="EMRGen.Infrastructure.Repositories.Providers.ProviderRepository, EMRGen.Infrastructure.Repositories" />
<typeAlias alias="ProviderGenericRepositoryInterface" type="EMRGen.Infrastructure.Data.IRepository`1[[EMRGen.Model.Provider.IProvider, EMRGen.Model]], EMRGen.Infrastructure" />
<typeAlias alias="ProviderGenericRepositoryConcrete" type="EMRGen.Infrastructure.Repositories.EntityFramework.ApplicationRepository`1[[EMRGen.Model.Provider.Provider, EMRGen.Model]], EMRGen.Infrastructure.Repositories" />
<!-- Provider Mapping-->
<typeAlias alias="ProviderInterface" type="EMRGen.Model.Provider.IProvider, EMRGen.Model" />
<typeAlias alias="ProviderConcrete" type="EMRGen.Model.Provider.Doctor, EMRGen.Model" />
Illustrate the call being made inside my class:
public class PrescriptionService
{
PrescriptionService()
{
IUnityContainer uc = UnitySingleton.Instance.Container;
UnityServiceLocator unityServiceLocator = new UnityServiceLocator(uc);
ServiceLocator.SetLocatorProvider(() => unityServiceLocator);
IProviderRepository pRepository =
ServiceLocator.Current.GetInstance<IProviderRepository>();
}
}
public class GenericRepository<IProvider> : IRepository<IProvider>
{
}
public class ProviderRepository : IProviderRepository
{
private IRepository<IProvider> _genericProviderRepository;
//Explict public default constructor
public ProviderRepository(IRepository<IProvider> genericProviderRepository)
{
_genericProviderRepository = genericProviderRepository;
}
}
What you want to do is possible, but you need to tell Unity how to map from interfaces to concrete types. AFAICT, your current configuration registers a lot of types, but doesn't specify how they relate to each other.
That said, static Service Locator is an anti-pattern. Consider changing your code to use proper Constructor Injection instead. That would also simplify your code considerably:
public class PrescriptionService
{
private readonly IProviderRepository pRepository;
public PrescriptionService(IProviderRepository pRepository)
{
if (pRepository == null)
{
throw new ArgumentNullException("pRepository");
}
this.pRepository = pRepository;
}
}
Using Unity, you would be able to wire it up like this:
var container = new UnityContainer();
container.RegisterType<PrescriptionService>();
container.RegisterType<IProviderRepository, ProviderRepository>();
container.RegisterType<IRepository<IProvider>, MyRepository<IProvider>>();
var ps = container.Resolve<PrescriptionService>();
Configure the container and resolve all components in the application's Composition Root.
You should only use XML configuration if you need to be able to change certain components without recompiling your application.
How do you handle primitive types when using a IoC container?
I.e. given that you have:
class Pinger {
private int timeout;
private string targetMachine;
public Pinger(int timeout, string targetMachine) {
this.timeout = timeout;
this.targetMachine = targetMachine;
}
public void CheckPing() {
...
}
}
How would you obtain the int and string constructor arguments?
Make another interface for this.
Then you will get something like:
public Pinger(IExtraConfiguration extraConfig)
{
timeout = extraconfig.TimeOut;
targetmachine = extraconfig.TargetMachine;
}
I don't know about other IOC containers, but Castle Windsor resolves these extra constructor parameters automatically.
I'm not sure if your difficulty is the value types or the concrete type. Neither is a problem. You don't need to introduce a configuration interface (it's useful if you want to pass the same parameters to multiple objects, but not in the case you've given). Anyway, here's the Windsor fluent code, I'm sure someone will submit an XML version soon.
container.Register(
Component.For(typeof(Pinger))
.ImplementedBy(typeof(Pinger)) // This might not be necessary
.Parameters(Parameter.ForKey("timeout").Eq("5000"),
Parameter.ForKey("targetMachine").Eq("machine")
)
);
It depends. The IoC-Container StructureMap will allow you to declare those dependencies when you configure the instance at the beginning of your execution.
e.g. in a registry
ForRequestedType<Pinger>()
.TheDefault.Is.OfConcreteType<Pinger>()
.WithCtorArg("timeout").EqualTo(5000)
.WithCtorArg("targetMachine").EqualToAppSetting("machine");
In Spring, one can look up property values from a property file using ${propertyName} notation
<bean class="blah.Pinger">
<constructor-arg value="${blah.timeout}"/>
<constructor-arg value="${blah.targetMachine}"/>
</bean>
In Spring.net the same functionality is provided by the PropertyPlaceholderConfigurer, which has the same syntax, and uses name value sections in config files.