Redirecting to a controller with sub-actions - asp.net-mvc

I'm completely new to MVC, so pardon if I'm using the wrong terminology. I'm building a controller that uses the following format, to display a project, and a step within that project.
Note: I'm using MVC5 which uses the newly introduced route attributes.
'/project/1/step/2
<Route("{ProjectID}/Step/{StepNumber:int}")>
Function ProjStep(ProjectID As String, StepNumber As Integer) As String
Return String.Format("Project {0} Step {1}", ProjectID, StepNumber)
End Function
The above works as expected. But I also want to handle the case where a user only specifies the project and not the step.
'/Project/1
<Route("{ProjectID}")>
Sub Projuate(ProjectID As String)
'Automatically start the user at step 555
'How do I send the user to the URL /Project/ProjectID/Step/555
End Sub

Apologies if syntax is a bit off - I do my MVC in C#.
You can either call the step Action directly or redirect to it.
Former (this will leave URL as /Project/1):
Function Projuate(projectID As String)
Return ProjStep(projectID,555)
End Sub
Latter (will end up on /Project/1/Step/555):
Function Projuate(projectID As String)
Return Redirect(Url.Action("ProjStep", new{ ProjectID = projectID, StepNumber=555})
End Sub
I don't know whether T4MVC works with VB but I would check that out - as it means you can get rid of those magic strings and get some nice extensions for creating URLs.
EDIT NOTE: Changed Sub to Function.

Just add the default value to the route is probably the easiest way:
<Route("{ProjectID}/Step/{StepNumber:int=555}")>
Function ProjStep(ProjectID As String, StepNumber As Integer) As String
Return String.Format("Project {0} Step {1}", ProjectID, StepNumber)
End Function
p.s. I hope it comes after the int - it might be StepNumber=5:int for all I know.

Related

Language-ext: chain Either<L, R> with Option?

I am just starting with language-ext, trying to use it in my Azure Function.
In this function, I first parse/validate the POSTed data from the HTTP request using some validator.
This validator returns an Either<ValidationErrors, RequestModel>.
Then I would like to chain onto the either result a service call that should use the request model to grab some data from an API an return an Option.
At the end of the chain I would then like to return an IActionResult BadRequest if there were ValidationErrors in the first step, or otherwise perform a Match on the result of the service call Option to either return a NotFoundResult or ObjectResult.
The issue I run into is that if I want to chain my service call (using Bind, or BiBind) after the Either<ValidationErrors, GetRequestModel>, then the signature of my service method must be some Either<ValidationErrors, ...>, which is incorrect, since my service method has nothing to do with ValidationErrors. It should just return an Option.
So I guess my question is how can preserve any ValidationErrors until the end of the chain, and be able to chain my service call with a Option signature onto an Either?
You have to decide what the result of your chained expression is.
Option:
var maybeResult = from validated in GetValidationResult(...).ToOption()
from apiResult in ApiCall(...)
select apiResult;
Either:
var resultOrError = from validated in GetValidationResult(...)
from apiResult in ApiCall(...).ToEither(*LEFT*)
select apiResult;
You have to replace *LEFT* by some error value or error generating function returning same type like left type of GetValidationResult.
Replace above pseudo code with your own code and look at the return types of the functions used above to see what's going on.
The reason why you need a common left type is that the bind operation can return some left (error) of first (GetValidationResult) or second (ApiCall) function call -- or right of your last (ApiCall) function if your reach successful end of your chain.
Recommendation: If you mix different left (error) return types you might want to use some thing like LanguageExt's built-in Error type or maybe just a plain string (or Exception).
Either with string as error type:
var resultOrError = from validated in GetValidationResult(...).MapLeft(Prelude.toString)
from apiResult in ApiCall(...).ToEither("api call failed")
select apiResult;
Additional note: I use LINQ style here, you can use method style:
var resultOrError = GetValidationResult(...)
.MapLeft(Prelude.toString)
.Bind(validated => ApiCall(...)
.ToEither("api call failed"));

Why does Gambas give me an error after I Dim a variable after a function call?

I'm playing around with gambas.
This code gives me the error "unexpected dim in FMain.class:6"
Public Sub Form_Open()
Print "this won't work"
Dim nickname As String = "gambas"
Print "Your new name is " & nickname
End
This code doesn't, and runs fine:
Public Sub Form_Open()
Dim nickname As String = "gambas"
Print "Your new name is " & nickname
End
Does gambas have requirements where variables are declared like pascal? I can't find any mention of it in the documentation. Thanks.
Gambas requires all DIM statements to be placed before any executable code inside a function or Subroutine (emphasis mine):
http://gambaswiki.org/wiki/lang/dim
All DIM declarations must be in the FUNCTION or SUB before the first executable command.
So change your code to this:
Public Sub Form_Open()
Dim nickname As String = "gambas"
Print "this will work"
Print "Your new name is " & nickname
End
Gambas' requirement for forward declaration of all local variables is very old-school. Sometimes it does make it easier to make self-documenting code and it incentivizes making functions short, but if a function has many intermediate short-lived local variables that cannot be immediately initialized (e.g. inside nested loops inside a function) then it hinders readability. YMMV.
This is not required anymore since Gambas 3.12.
But I suggest to continue declaring variables at the top function. It makes the code far more readable two years later.

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.

T4MVC 2.6.65 and UseLowercaseRoutes=true error

Good day!
I'm using latest T4MVC from 2.6.65 from NuGet (upgraded from 2.6.64), I've set
// If true, use lower case tokens in routes for the area, controller and action names
static bool UseLowercaseRoutes = true;
And I got error:
The expression being assigned to '....' must be constant ...\T4MVC.cs
Here is the the generated code that triggers error:
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionNameConstants {
public const string Calc = ("Calc").ToLowerInvariant();
}
Is this a bug?
Ah sorry, the previous change broke it. I just pushed a new build of T4MVC (2.6.66) which addresses this. Well, it's more of a workaround as it basically doesn't generate the constant tokens when UseLowercaseRoutes is used. But that'll get us going for now.
The root of the problem is that C# doesn't support using .ToLowerInvariant() in constant strings. Ideally, it would just evaluate that at compile time, but it's not that smart :)

URL-encode parameters in ActionLink?

I have the following route registered;
routes.MapRoute(
"LocationsByArea",
"Locations/{system}/{storage}/{area}",
new { controller = "StorageLocation", action = "Index" },
null
);
...and the following code in my view;
<%= Html.ActionLink("Platser", "Index", "StorageLocation", new { system = Model.System, storage = Model.Storage, area = item.Name }, null)%>
My problem is when the "area = item.Name" contains a colon, e.g. "Area 4:1". If I click the rendered link I get HTTP-error 400, Bad reqest. I guess I have to encode my area parameter in some way, but I cant figure out how. Any help is apreciated.
Thanks!
The built-in encoding/decoding does not work, so I suggest you roll your own, like this:
namespace MyProject.Helpers
{
public static class JobNameHelper
{
public static string JobNameEncode(string jobname)
{
return jobname.Replace(":", "---colon---");
}
public static string JobNameDecode(string jobname)
{
return jobname.Replace("---colon---", ":");
}
}
}
Can you not just use
Server.UrlEnconde(item.Name)
Or am I missing something?
In your routing you may have to use Server.UrlDecde as well although I think It should decode for you on request.
Try using the Routing Debugger to see what the url router is getting passed, then you can see where the decoding needs to happen
ASP.NET 3.5 SP1 and earlier have a number of restrictions on which URLs are valid. In ASP.NET 4 most of these issues have been fixes (or are at least customizable via web.config). I think that the colon character, even when encoded, might not be allowed in ASP.NET 3.5 SP1 and earlier due to security concerns. Allowing colons can be a security problem when performing file checks since they are a little-known syntax for NTFS Alternate Data Streams.
I recommend trying to choose a character other than a colon for these purposes. Maybe a comma, semi-colon, or equal sign might work instead?

Resources