Use VB.Net module inside MVC 5 Razor page - asp.net-mvc

I have a module written in VB.Net that has several read-only properties. It looks like this:
Module Name1
Public ReadOnly Property ClientID As String
Get
Return "[some data here]"
End Get
End Property
Public ReadOnly Property ClientKey As String
Get
Return "[some data here]"
End Get
End Property
End Module
Nothing real fancy here. What I'm trying to do is use this module in an MVC 5 Razor page like this:
<span>#Name1.ClientID - #Name1.ClientKey</span>
Again, nothing fancy. But running the code produces the following error:
Name1 is not accessible in this context because it is 'Friend'.
Modules have friend access by default, which prevents them from being accessible outside of the current assembly. This is what I want. But it doesn't work when called from a Razor page. I've check to ensure that the namespaces were imported and such but no go. (Changing the module's access to public gets things working but I don't wish to make it public.)
What am I doing wrong?

I found a solution to my problem here: ASP.NET MVC: How to set global ViewBag properties and have them available in each View
By creating a custom ActionFilter, I was able to set ViewBag properties and set their values to the properties in my module. Then I added that filter to the GlobalFilters collection. From there, I can access the ViewBag properties easily in Razor pages.

Related

Grails Custom Scaffolding get access to controller name

I am trying to write a custom src/templates/scaffolding/Controller.groovy and was wondering if there was any way to get access to the controller name? Right now it seems like you can only get the "model" class. The reason I need it is I am customizing the render to prefix the templates directory based on the controller.
For instance I have a controller named AuthorAdminController and I need to customize the list to use the /admin/user/** directory.
Let me know if you have any questions. I am getting ready to look into how to customize DefaultGrailsTemplateGenerator but I am not sure if that is the correct route to go.
Example:
class UserAdminController {
static scaffold = User
}
Currently in my Controller.groovy I get className='user' so I have no access to the controller.
I don't think you can, as the way scaffolding works your template will always be generating a class named DomainClassNameController (i.e. UserController in your example), which gets loaded into a new classloader and then the metaclass of the real controller (UserAdminController) gets new actions added to it which delegate to an instance of the generated UserController.
Now every controller has access to the controllerName property during execution of actions, so this may provide you with a workaround. I haven't tried it, but you could try putting a log.info("controller: \${controllerName}") into the template and see which name it gives you (the backslash to make it resolve at runtime rather than generation time).

how to do Localization for one of the #Model property in mvc3

I have started working on an MVC project and I came across some scenarios where I feel I am stuck. I need to convert the existing MVC3 site to work for multiple language.
I have one HeaderPage.cshtml and it has a view model bound to it by
#model IHeaderPage
And it outputs a property of this model:
<h3>#Model.HeaderName</h3>
I called this view from MainPage.cshtml
#Html.Partial("HeaderPage")
Now in the Controller's Action method I change the model's property
objHeaderPage.HeaderName="Fill your Registeration details";
And when i run the project i see the the text "Fill your Registeration details".
Now how can I change the text value, i.e. it should read from my resx file.
I have already created resx files in App_LocalResources folder.
I heard that, it can be done by Display Attribute.. but how do i do that or is there any other better way?
This should answer your question regarding the use of DisplayAttribute.
I use DisplayAttribute for every property of my ViewModel, but if you have to handle custom messages like "The record can not be saved because of an error...", or something similar, you can simply use
objHeaderPage.HeaderName = Resources.ResourceMessageName;
The framework will choose automatically the correct culture.
I prefer to put all my resources in a separate projects so I can deploy only the dll of the resources in case of need, but you can also think to deploy the resx files to edit them directly on the production machine. I guess it's up to what you prefer/need.
use System.ComponentModel.DataAnnotations Namespace in ViewModel.
[Display(Name="Fill your Registeration details")]
public string HeaderName{get;set;}
also you can use your resource file. Just review http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.aspx

Is it possible to get the controller and the action (NOT THEIR NAME!!) based on the url?

I have found a dozens of threads about getting the name of the controller and method based on the url, I managed that just as well. Can I get the MethodInfo of the method based on their name automatically from the MVC engine, or do I have to do Type.GetType("Namespace.Controllers."+cname+"Controller").GetMethod(mname)? Which is not so nice, since how do I know the namespace in a framework class? How do I know if the default naming patterns are being observed, or is there a different config in use?
I want to get a "What Would MVC execute?" kind of result....
Is it possible?
EDIT: further info:
I have a framework which uses translatable, data-driven urls, and has a custom url rewriting in place. Now it works perfectly when I want to show the url of a news object, I just write #Url.Content("~/"+#Model.Link), and it displays "SomeNewsCategory/SomeNews" instead of "News/29" in the url, without the need to change the RouteTable.Routes dynamically. However in turn there is a problem when I try to write RedirectToAction("SomeStaticPage","Contact"); into a controller. For that, I need to register a static link in db, have it target "/SomeStaticPage/Contact", and then write
Redirect("~/"+DB.Load(linkid).Link); and that's just not nice, when I have 30 of these IDs. The web programmer guy in the team started registering "fake urls", which looked like this:
public class FakeURL
{
public string Controller;
public string Action;
public int LinkID;
}
and then he used it like Redirect(GetFakeUrl("controller","action")); which did the trick, but still was not nice. Now it got me thinking, if I apply a [Link(linkid)] attribute to each statically linked method, then override the RedirectToAction method in the base controller, and when he writes ReturnToAction("action","controller"), I'll actually look up the attribute, load the url, etc. But I'm yet to find a way to get the methodInfo based on the names of the controller and the action, or their url.
EDIT: I've written the reflection by myself, the only thing missing is getting my application's assembly from inside a razor helper, because the CallingAssembly is the dinamically compiled assembly of the .cshtml, not my WebApplication. Can I somehow get that?
To answer your edit, you can write typeof(SomeType).Assembly, where SomeType is any type defined in code in the project (eg, MvcApplication, or any model or controller)
Also, you can write ControllerContext.Controller.GetType() (or ViewContext) to get the controller type of the current request EDIT That's not what you're trying to do.
I found out that it was totally wrong approach. I tried to find the type of the controller based on the name, when instead I had the type all along.
So instead of #Url.Action("SomeAction","SomeController") I'll use #Url.MyAction((SomeController c)=>c.SomeAction()), so I won't even have to find the controller.

Preferred way to use config settings in asp.net mvc master page

My Problem: I have an MVC3 application where all views use a common master page. The master page has many links to other (internal) sites. I need to be able to change the domain of these links depending on the deployment environment (e.g. staging.blah.com, www.blah.com, dev.blah.com etc). This domain is stored in the web.config.
There are numerous ways of doing this, but I am looking for some sort of consensus as to the preferred method. Here are some options but I am open to any suggestions:
(1) reference appsettings from master page directly. This is the simplest and most common approach but I am not particularly keen on reading the web.config and concatenate the url throughout the master page code. In fact, I am not sure that I like the idea of the view accessing the web.config at all.
(2) stick the appsetting value in viewdata/viewbag using a custom action filter which reads the config. concatenate in the page as before.
(3) as (2), but inject appsetting value in via contructor injection rather than reading it within the filter.
(4) create a base class for all my strongly typed viewmodels and populate with the appsetting using a custom action filter.
(5) create an htmlhelper that takes in the path and internally reads the appsetting and concatenates.
(6) create a custom view base class, inject in appsetting value and make available as property or function that takes in path and concatenates.
Just to add that typically when the master page requires data, I like to use Html.Action, but this is not possible in the case of these URLs that are used throughout the master page.
Thoughts?
(5) create an htmlhelper that takes in the path and internally reads the appsetting and concatenates.
I would go with this one. Your custom HTML helper could look something like this:
<%= Html.ExternalActionLink(
"link text",
new { path = "/foo/bar.php" }
new { param1 = "value1", param2 = "value2" }
) %>
and could emit the following HTML:
link text
What I have done in the past is use viewdata/viewbag in my master page and populate its values in my base controller. The base controller in turn called another class to do the work of reading the values from the web.config.
This way the view is pretty clean (e.g. it does not contain code to read appsettings) and I don't need to create a base view model that matches all my views that use the master.
This approach has the disadvantage that uses a viewdata/viewbag but I decided that was OK in my case and extremely easy to implement.

Adding Custom attributes to the page directive in asp.net-mvc

I have created a base class that derives from ViewPage with a custom public attribute that I want to be able to set in the #page directive however I am getting the following error.
Error 24 Error parsing attribute 'attrame': Type 'System.Web.Mvc.ViewPage' does not have a public property named 'attrname'.
the directive looks as so
<%# Page Title="" Language="C#" AttrName="Test" Inherits="Web.Helpers.Views.BaseViewPage" %>
The problem seems to be that it doesn't recognize the base class from the Inherits tag. I thought this should work from reading around on the internet. Has anyone else tried this or have any idea why this isn't working?
This is unfortunately not supported in ASP.NET MVC 1.0 or ASP.NET MVC 2.
The reason for this is an implementation detail of some MVC-specific parser logic that is used in ASPX/ASCX/MASTER files. If the view page's (or view master page's or view user control's) base type is a generic type there is logic that hard-codes the base class for the ASP.NET parser's sake to be just regular ViewPage (or ViewMasterPage or ViewUserControl).
Because the ASP.NET parser looks at the base class that MVC tells is, it will only ever be ViewPage, and thus it doesn't recognize the new property that you added, and thus it reports an error.
It is worth mentioning that this applies only if the base class you specify in the view page is generic. If you use a non-generic type then it should work just fine and you should be able to set values on custom properties.
I can think of two workarounds:
1) Create custom page base types for every type you need. This solution is rather easy, though cumbersome:
public class MyBasePage<TModel> : ViewPage<TModel> {
...
}
public class CustomerPage : MyBasePage<Customer> { }
public class ProductPage : MyBasePage<Product> { }
And then use only the non-generic derived types in the view pages' "inherits" attribute.
2) Copy the MVC source code (see links below) from the ViewTypeParserFilter into your project and make some small changes. The key method to change is the PreprocessDirective() method. Towards the bottom is an if() statement that overrides the "inherits" attribute to be one of a few hard-coded values. As you'll see, this code runs only if the declared base type is generic (hence my earlier comment).
It's up to you to decide exactly how you want to change this code. The key thing here is that the type name must be a type that .NET's Type.GetType() method can understand. That is, you have to use the CLR syntax for constructs such as generics and not the C# or VB syntax. For example, while in C# you can say:
System.Web.Mvc.ViewPage<Customer>
In the CLR syntax it's something like:
System.Web.Mvc.ViewPage`1[MyApp.Models.Customer]
Hopefully one of the two options above suits you.
Source code links:
ASP.NET MVC 1.0 source code download
ASP.NET MVC 2 RC source code
You need to set the base type in the web.config to get around this. Go to
/Views/Web.config
and change the
configuration/system.web/pages
and change the attribute pageBaseType to your class.
<pages pageBaseType="Web.Helpers.Views.BaseViewPage" {your other attributes here} />

Resources