How can I map controller endpoints to actions on F#? - f#

I am probably missing something here as I am new to F#, however, I need the following:
open Microsoft.AspNetCore.Mvc
[<ApiController>]
[<Route("[controller]")>]
type MyController () =
inherit ControllerBase()
//[<HttpGet(Name = "Ip")>] doesn't work neither.
[<HttpGet>]
[<Route("[controller]/[action]")>]
member _.Ip() =
"192.168.199.2"
The URL: https://localhost:5001/my/ip should return: 192.168.199.2.
The error message I am getting instead:
{"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1","title":"One or more validation errors occurred.","status":400,"traceId":"00-389e8d2f6bc3a342a3754b5c5ce7915f-7e6e851c78f47c4f-00","errors":{"id":["The value 'ip' is not valid."]}}

I don't have much experience with ASP.NET Core, but I think the problem is that you have a route set at both the class and member level. These are additive, so the actual URL of your Ip action is currently https://localhost:5001/my/my/ip.
To fix this, remove the Route attribute entirely from the class level, or remove the [controller] prefix from your member-level route:
[<ApiController>]
[<Route("[controller]")>] // controller is specified here, so...
type MyController() =
inherit ControllerBase()
[<HttpGet>]
[<Route("[action]")>] // ...no controller specified here
member _.Ip() =
"192.168.199.2"

Related

Defining member as event handler in F#

This is probably asked several times but I just can't find an example.
My goal is to define an event handler for an event and the handler should be a member of the class. In other words I don't want to use function since I need to access instance variables and members
The latest variation I've tried:
namespace A
type ValueList<'TValueItem when 'TValueItem :> IValueItem>() =
inherit System.Collections.ObjectModel.ObservableCollection<'TValueItem>()
// This is causing error: The value or constructor 'ValueList_CollectionChanged' is not defined
let collectionChangedHandler = new System.Collections.Specialized.NotifyCollectionChangedEventHandler(ValueList_CollectionChanged)
// Constructor code
do base.CollectionChanged.AddHandler(collectionChangedHandler)
// Handles collection changed events for data items
member this.ValueList_CollectionChanged(sender : obj, e : System.Collections.Specialized.NotifyCollectionChangedEventArgs) =
// The code I want to run goes here
...
Or is this maybe a completely wrong approach?
Looks like you're looking for the self-identifier syntax:
type ValueList<'TValueItem when 'TValueItem :> IValueItem>() as this =
The as this (or any other identifier in place of this) allows to refer to the instance being constructed from the constructor.
You could then change your other lines to use the identifier:
let collectionChangedHandler = new System.Collections.Specialized.NotifyCollectionChangedEventHandler(this.ValueList_CollectionChanged)
do this.CollectionChanged.AddHandler(collectionChangedHandler)
For this to be valid as-is, the ValueList_CollectionChanged method also needs to be in curried form:
member this.ValueList_CollectionChanged (sender : obj) (e : System.Collections.Specialized.NotifyCollectionChangedEventArgs) =
As an alternative to using curried arguments, you can use a lambda to transform the arguments where the handler is instantiated, e.g. .NotifyCollectionChangedEventHandler(fun sender e -> this.(...).

Spray Routes within Routes

I have an app that is built using Spray.io.
I have a number of routes and at the moment I am repeating some of the routing logic within each route. I want to extract this logic out to a route higher up the chain while keeping each route/endpoint in a logically separate class.
This is an example of what I am currently trying...
ServiceActor...
def receive = runRoute(v1Routes)
V1Routes.scala (trait extending HttpService with other route traits)
val v1Routes =
pathPrefix("v1") {
authenticate(...) {
myRoutes1 ~ myRoutes2
}
}
MyRoutes1.scala
val myRoutes1 =
pathPrefix("route1") {...}
MyRoutes2.scala
val myRoutes2 =
pathPrefix("route2") {...}
This compiles fine but the routes from MyRoutes1 and MyRoutes2 don't seem to get added into v1Routes as I would have hoped.
How do I implement this type of routing logic?
Thanks

Why Moq verify method call throws exception?

I can't get this piece of code to pass.
[<Test>]
member public this.Test() =
let mock = new Mock<IList<string>>()
let mockObj = mock.Object
mockObj.Add("aaa")
mock.Verify(fun m -> m.Add(It.IsAny<string>()), Times.Once())
Exception I get:
System.ArgumentException : Expression of type 'System.Void' cannot be used for constructor parameter of type 'Microsoft.FSharp.Core.Unit'
I believe it has something to do with F# not inferring properly the data type of labda expression but I don't know how to fix that.
You are correct, this an issue with F# type inference when calling an overloaded method that accepts either Action or Func.
One option is to download the Moq.FSharp.Extensions from Nuget and change your Verify to an explicit VerifyAction, i.e.
open Moq.FSharp.Extensions
type MyTests() =
[<Test>]
member public this.Test() =
let mock = new Mock<IList<string>>()
let mockObj = mock.Object
mockObj.Add("aaa")
mock.VerifyAction((fun m -> m.Add(any())), Times.Once())
Underneath the covers the Moq.FSharp.Extensions simply defines an extension method VerifyAction that only takes an Action to avoid ambiguity:
type Moq.Mock<'TAbstract> when 'TAbstract : not struct with
member mock.VerifyAction(expression:Expression<Action<'TAbstract>>) =
mock.Verify(expression)
Another option is to use Foq, a mocking library with a similar API to Moq but designed specifically for use from F#, also available via Nuget:
[<Test>]
member public this.Test() =
let mock = Mock.Of<IList<string>>()
mock.Add("aaa")
Mock.Verify(<# mock.Add(any()) #>, once)

VB.NET MVC Overload resolution failed because no accessible 'Create' accepts this number of arguments

I'm using VB.NET MVC 5 with Identity 2.0.
I've been trying to configure my Startup.Auth to automatically use a single instance of ApplicationDbContext, CustomUserManager and CustomRoleManager per request as detailed in this tutorial.
My code is as follows: (minus garbage)
Public Sub ConfigureAuth(app As IAppBuilder)
app.CreatePerOwinContext(ApplicationDbContext.Create)
' Error 135 Overload resolution failed because no accessible 'CreatePerOwinContext' can be called with these arguments:
' Extension method 'Public Function CreatePerOwinContext(Of T)(createCallback As System.Func(Of Microsoft.AspNet.Identity.Owin.IdentityFactoryOptions(Of T), Microsoft.Owin.IOwinContext, T)) As Owin.IAppBuilder' defined in 'Owin.AppBuilderExtensions': Data type(s) of the type parameter(s) cannot be inferred from these arguments. Specifying the data type(s) explicitly might correct this error.
' Extension method 'Public Function CreatePerOwinContext(Of T)(createCallback As System.Func(Of T)) As Owin.IAppBuilder' defined in 'Owin.AppBuilderExtensions': Data type(s) of the type parameter(s) cannot be inferred from these arguments. Specifying the data type(s) explicitly might correct this error.
app.CreatePerOwinContext(Of CustomUserManager)(CustomUserManager.Create)
' Error 136 Overload resolution failed because no accessible 'Create' accepts this number of arguments.
....
End Sub
But recieve these errors no matter what I do
Overload resolution failed because no accessible 'Create' accepts this number of arguments.
I think it's to do with me writing in VB and the example being in C#, though it infuriates me that this is a problem. My CustomUserManager is a Public Class, and the Create method is Public Shared.
Public Shared Function Create(options As IdentityFactoryOptions(Of CustomUserManager), context As IOwinContext) As CustomUserManager
Dim manager As CustomUserManager
manager = New CustomUserManager(New CustomUserStore(context.Get(Of ApplicationDbContext)()))
manager.UserValidator = New UserValidator(Of ApplicationUser, Integer)(manager)
manager.PasswordValidator = New PasswordValidator() With {
.RequiredLength = 6
}
manager.RegisterTwoFactorProvider("EmailCode",
New EmailTokenProvider(Of ApplicationUser, Integer)() With {
.Subject = "Security Code",
.BodyFormat = "Your security code is: {0}"
}
)
manager.EmailService = New EmailService()
manager.SmsService = New SmsService()
If Not options.DataProtectionProvider Is Nothing Then
manager.UserTokenProvider = New DataProtectorTokenProvider(Of ApplicationUser, Integer)(options.DataProtectionProvider.Create("ASP.NET Identity"))
End If
Return manager
End Function
Any ideas anyone? Any help is much appreciated, Cheers.
Try this
Public Sub ConfigureAuth(app As IAppBuilder)
app.CreatePerOwinContext(AddressOf ApplicationDbContext.Create)
End Sub
The AddressOf operator creates a function delegate that points to the function specified by procedurename
link1
link2
If you have already updated your visual studio 2013 with Update 3. This comes with all the identity stuff and custom user manager, role manager and many more.
Create new project using MVC template and Authentication selected as Individual User Accounts using Visual Studio 2013. Then you will get created all the code same as you have already implemented using the example. You can use that classes and implementation in order to fix your issues with your custom user manager.
Check the floder App_Start >> IdentityConfig.vb
Only thing I can see in your code, you have used integer as Id rather than string. That won't be a problem if you have correctly bind EF model biding stuff.

Is there any way in Struts 2 by which I can get all namespaces in my app?

Is there any way in Struts2 by which I can get list of namespaces in my App ?
I want this as set or list at runtime .
I am using Struts2 RestActionMapper plugin.
When there invalid namespace is specified for valid action, Struts is throwing namespace error.
But I could not redirected to standard error page when this error occurs. I tried almost all options e.g.global error mapping default namespace etc . Nothing worked. So thought it would be great if I could get list of namespaces in my app, thus i could have checked invalid namespace against my list of valid namespaces and accordingly I could have thrown generic error which would finally result in my standard error page.
I am looking for how to get list of all namespaces in my project.
So basically I want to do something like this.
validNamespaces = getNamespaces();
if(validNamespaces.contains(namespaceRetrivedFromRestPlugin))
{Sysout("This is valid namespace.")}
else
{Sysout("Invalid namespace");}
This is possible, though like Steven has pretty much stated, I'm not convinced that this is the right approach to the problem you state of redirecting to an error page. But, I'll leave that part up to you and use this space to answer the namespace question.
This code will have to be in a Struts2-created object for the injection to work.
private Configuration configuration;
#Inject
public void setConfiguration(Configuration config) {
this.configuration = config;
}
protected Set<String> getNamespaces() {
Set<String> namespaces = Collections.emptySet();
Map<String, Map<String, ActionConfig>> allActionConfigs = this.configuration.getRuntimeConfiguration().getActionConfigs();
if (allActionConfigs != null) {
namespaces = allActionConfigs.keySet();
}
return namespaces;
}
The configuration can also be obtained from a ConfigurationManager. Also, you would obviously want to store these in a variable rather than calling above method over and over. If your object is, say, an interceptor, then you could call this method from the init() method and store it in a class-level variable.

Resources