In the Wicket Application class I have mounted a page at the location /about
mountBookmarkablePage("about", AboutPage.class);
I verify that the about page is available at /about. Then in the page which needs a link to the about page, I use the Wicket Link class:
add(new Link("link") {
#Override
public void onClick() {
setResponsePage(AboutPage.class);
}
};
)
The links work as expected but the target URL diplayed in the browser status bar when the mouse is over the link looks like
http://localhost:8080/?wicket:interface=:0:linkpage:repeating:1:link::ILinkListener::
A workaround which I have found is to use ExternalLink
new ExternalLink("link", "/about", "about");
This changes the target URL to
http://localhost:8080/about
which is displayed in the browser status bar when the mouse is over the link.
Is there a way to use the mounted URL as the target link with Wicket Link class, or is there a way to get the mount location for a class, so that I can use it to build the link url for AboutPage.class (instead of hard coding it in the ExternalLink constructor)?
For this purpose you should use BookmarkablePageLink (as you're saying you're doing), to set the link label (or any other content for that matter) just call .add(Component... c) since BookmarkablePageLink is actually a MarkupContainer.
So, to create a link to AboutPage.class you need to do this:
BookmarkablePageLink aboutLink = new BookmarkablePageLink("link", AboutPage.class);
aboutLink.add(new Label("linkText", "Go to About page"));
add(aboutLink);
and the matching markup
<a wicket:id="link"><span wicket:id="linkText">Link text goes here</span></a>
Yeppers, it's slightly more verbose but also very easily extensible. If you want to, you can create your own convenience subclass of BookmarkablePageLink called BookmarkableTextLink and have a
new BookmarkableTextLink(String id, Class<Page> pageClass, String linkText);
constructor for it.
Found a solution: the BookmarkablePageLink class
add(new BookmarkablePageLink("link", AboutPage.class));
This solution only has a small problem: the link label can not be set, maybe this can be done by assigning a model.
Related
I added a default MvcApplication (MVC 4) (its name is MvcApplication3 matching the name of my solution's) width Home views (About, Index, Contact) and that will be my startup (bold in VS solution explorer's interface) project. Then I added another project (MvcApplication, but this time an empty one) called MvcApplication2 to the solution. Then I added the latter project as a reference to the first. I also added a controller called TestController (green line) to the referenced project and generated a view for its Index (red arrow) method. However, when I go to a link /Test or /Test/Index, the view I am expecting (red arrow) is not shown. Then I added the same folder Test with Index.cshtml (blue arrow) to the main project and now I am seeing its contents rather than the project's where my controller sits in.
Is it possible to make the application look for the views in the other project rather than the startup one?
I am adding the image of the structure to make it easier to follow.
P.S.: probably related: the breakpoint IS being hit in the Index method of TestController.
tldr; blue view is used instead of a red one
I think your problema is that you have set MvcApplication3 as startup Project and is causing you to open the view off that Project.
Is it possible to make the application look for the views in the other
project rather than the startup one?
Yes its posible, you can redirect your application the url. Think this your application have a url http://localhost:(someport) you can set redirect to the port of the second application.
I put a link to for better understanding a routing system of MVC: Documentation of routing system
As far as I know, you can't link to projects together like that. Each project becomes its own website with its own address. The reason you might put multiple projects together in one solution is to share things like classes, services, etc. I think what you're needing is areas:
http://www.codeproject.com/Articles/714356/Areas-in-ASP-NET-MVC
With some ideas from me and a friend of mine and a link about overriding RazorViewEngine I finally got what I wanted working exactly how I was expecting it to:
I created a folder named ViewsBase in the main project.
I rewrote RazorViewEngine this way: I only changed the place that was needed for me, leaving everything else like I found in the constructor of RazorViewEngine:
public class MyCustomViewEngine : RazorViewEngine
{
public MyCustomViewEngine()
{
...
ViewLocationFormats = new[]
{
"~/Views/{1}/{0}.cshtml",
"~/Views/{1}/{0}.vbhtml",
"~/Views/Shared/{0}.cshtml",
"~/Views/Shared/{0}.vbhtml",
"~/ViewsBase/{1}/{0}.cshtml",
"~/ViewsBase/{1}/{0}.vbhtml"
};
...
(I find it rather disturbing how I am unable to format the code properly. Can someone give me a hand please?)
and in Global.asax of the main project I added:
ViewEngines.Engines.Clear();
var ourViewEngine = new
ViewEngines.Engines.Add(ourViewEngine);
AreaRegistration.RegisterAllAreas();
...
I added a post-build event command:
xcopy /s "$(ProjectDir)Views\*.*" /Y "$(SolutionDir)$(SolutionName)\ViewsBase\"
It started looking for the views in the expected order
I added a ViewStart file to the base project to make it render the Layout too.
I'm writing an image uploader in Java Play! in the style of
https://gist.github.com/1256286#file-picture-java-L3
This is great. The image is rendered using this function in the Controller object (here, Picture is a Model implementation that has metadata about an image file:
public static void show(Long id) {
Logger.info("loading id=%s", id);
Picture picture = Picture.findByKey(id);
response.setContentTypeIfNotSet(picture.contentType);
renderBinary(new ByteArrayInputStream(picture.file), picture.file.length);
}
I want to add a url member to Picture that contains the absolute URL to this function for a given picture. How can I populate this member in a way that works irrespective of where the Java Play! application is hosted?
Although I didn't try it in version 1.x I suggest to check the Router API, there are some methods which indicates, that they can optionally create an absolute route (I'm Play 2 user and have no experience with them).
There are also methods like ie. getBaseUrl() or getFullUrl(String action, Map<String,Object> args) so I just guess that they probably will help you to resolve the problem.
I am maintaining a JSF2 Ajax application and we are heavily using h:commandLinks and f:ajax tags for all actions - always only rerendering what is needed.
This does of course break the expected behaviour for the user when performing a right click on the links and choosing "Open Link in New Tab" etc.
I understand that f:ajax forces the href atribute of the resulting a element to be # and does all the magic post request trickery in the onclick function - I now want to provide fallback support for the "Open Link..." action by putting some meaningful link in the href attribute of the resulting <a> tag.
This would not break the "normal" onclick behaviour as the generated javascript always finishes with return false; but would allow me to send my users to some page using a normal GET request in case they want to open the link in a new window.
Is there a build in way to do this? Or could somebody point me in the right direction on where in the JSF lifecycle I would have to jump in to do this maybe using a phase listener?
Simplest would be to extend com.sun.faces.renderkit.html_basic.CommandLinkRenderer and override the renderAsActive() method accordingly. Mojarra is open source, just copy the method and edit the line where it says writer.write("href", "#", "href"). Replace the "#" string accordingly to your insight.
public class MyCommandLinkRenderer extends CommandLinkRenderer {
#Override
protected void renderAsActive(FacesContext context, UIComponent command) throws IOException {
// ...
}
}
To get it to run, register it as follows in faces-config.xml:
<render-kit>
<renderer>
<component-family>javax.faces.Command</component-family>
<renderer-type>javax.faces.Link</renderer-type>
<renderer-class>com.example.MyCommandLinkRenderer</renderer-class>
</renderer>
</render-kit>
Note that this tight couples your renderer to Mojarra. To be JSF implementation independent, you'd need to create a whole new renderer instead of extending a Mojarra specific renderer class.
Unrelated to the concrete problem, consider reading When should I use h:outputLink instead of h:commandLink?
I want to use MVC views to create the body for an email and I have come across this (http://www.brightmix.com/blog/renderpartial-to-string-in-asp-net-mvc/) but it doesn't seem to work with strongly typed views (ViewContext is null). But I was after something the would render a full view including a masterpage.
I thought that if there was a way of just invoking a view with out redirecting and just writing to a different stream and sending the email within the controller that might do it, but I can't work out how to invoke a view.
Any suggestions would be great!
Thanks in advance.
Gifster
The question has been asked (and answered) already:
Render View as a String
This is the bit that I use:
protected string RenderViewToString<T>(string viewPath, T model, System.Web.Mvc.ControllerContext controllerContext) {
using (var writer = new StringWriter()) {
var view = new WebFormView(viewPath);
var vdd = new ViewDataDictionary<T>(model);
var viewCxt = new ViewContext(controllerContext, view, vdd, new TempDataDictionary(), writer);
viewCxt.View.Render(viewCxt, writer);
return writer.ToString();
}
}
Best place for this method is in a class library project that your mvc project has a reference to. Mainly because that way you can easily reuse it in all your apps. But also because it is neither Application logic (so doesn't belong in the controller) nor does it belong in the model. Some things are just utilities.
Note that to get this to work, the viewPath parameter HAS to be the PHYSICAL PATH to the file, complete with the .aspx extension. You can't use a route as WebFormView class requires a physical path in its constructor.
This will render the full view and take account of the master page.
HEALTH WARNING FOR HTML EMAILS:
HTML emails and the devices where you read them are even more difficult and restrictive to design for than websites and browsers. What works in one, will not work in another. So with html emails, you really have to Keep It Simple! Your lovely page with menus and relative images and whatever else, JUST WON'T WORK in all email devices. Just as an example, the images src attribute needs to be absolute and include the domain:
This won't work:
<img src="/Images/MyImage.gif" ... />
Bit this will:
<img src="http://www.mywebsite.com/Images/MyImage.gif" ... />
With those caveats, it works fine and I use it. Just don't try to send them the full gimmickry of your website, cos that won't work!
Even more important:
All CSS must be INLINE and just for basic styling: colours, borders, padding. But no floating and positioning. CSS layouts won't work consistently across devices!
You can use MvcView NuGet package to do this! Its simple, just install using install-package MvcMailer and you are done! Use full power of view engine to template, master page, view model and send html emails neatly!
We have a requirement to have our ASP.NET MVC websites be automatically closed down by a remote notification (change in database value). Where would be the best place to implement this?
Base Controller Class
Global.asax
Custom attribute
Other
Update
Lots of suggestions to use app_offline but this scenario will be happening daily and will be purely initiated by the database so I would rather have the application take the initiative rather than something external push the file in.
Also, I will probably need to redirect the users to a holding page (preferably an MVC controller method to keep everything consistent). I'm leaning more towards catching it in my BaseController and having that handle it
There's a standard way of "gracefully" terminating ASP.NET 2.0 webapp - just drop a App_Offline.htm to the root directory of your application. See this.
I would go with Global.asax Application_BeginRequest if you have to do it programmatically.
You could Response.Redirect the page to "Offline.aspx" which can retrieve a message from the database or whatever you need. Of course you'd have to look at the request to see if it was trying to get to "Offline.aspx" otherwise you'd end up in an infinite loop.
Or maybe all your applications can be redirected to a single website which would remove most the complication.
I'm going to answer this myself as I did it a different way but thanks to everyone for their responses.
What I ended up doing is overriding OnActionExecuting() in my BaseController class (which all my controllers derived from).
In this method I check the database (using a 1 minute cache) and if the website is closed I load up a view to display a closed message. Code shown below
Protected Overrides Sub OnActionExecuting(ByVal filterContext As System.Web.Mvc.ActionExecutingContext)
MyBase.OnActionExecuting(filterContext)
Dim _cfgService = ObjectFactory.GetInstance(Of IConfigService)()
If _cfgService.DynamicConfig.WebSiteClosed Then
filterContext.Result = ErrorHandler(_cfgService.DynamicConfig.WebSiteClosedTitle, _
_cfgService.DynamicConfig.WebSiteClosedMessage)
End If
End Sub
Handling this type of behavior in the Global.asax file sounds like the best solution and redirecting to a static "ofline/closed" page. Handle the request on the Application_BeginRequest method, check to see the the site is active, if it let it continue, if it is not online Response.Redirect the request to the static page.
protected void Application_BeginRequest(object sender, EventArgs e)
{
string redirectURL = "~/Offline.aspx"; //some static page
bool isOnline = false; //SQL Call, config value
if (!isOnline && !string.IsNullOrEmpty(redirectURL))
{
Response.RedirectLocation = redirectURL;
Response.End();
}
}
Sorry, don't know about ASP.NET, but in case helpful:
We have a single APPLICATION.ASP page for our site (CMS / Database merge type stuff); this is possibly not common and therefore may therefore restrict usefulness, but could perhaps be implemented by an INCLUDE at the top of all ASPX files
We rename APPLICATION.ASP to TEST.ASP and copy HOLDING_PAGE.ASP to APPLICATION.ASP
The HOLDING_PAGE.ASP is present in the WWW folder, so always ready-and-available. It contains a "Site not available" message etc. and is self contained for all CSS (no include files, no DB access). Only exception is the company logo (which is external to that file, obviously)
This method prevents all access to the site, is not dependant on having a working DB connection, and allows us to change anything on the site without interfering with the holding page (apart from Company Logo, but changing that is likely to be benign)
We can still access the site, internally, using TEST.ASP - so we can test any new rollout features before removing the holding page and putting the site live. If you want to prevent anonymous use of TEST.ASP then deny anonymous permission.
Remove holding page is: Delete APPLICATION.ASP (i.e. the holding page) and Rename TEST.ASP to APPLICATION.ASP
We also have a database flag that causes the normal APPLICATION.ASP page to show a holding page - which we can use whilst doing more minor changes.