Access to ViewEngines.Engines.FindView Method in not web context - asp.net-mvc-3

I have question about access to FindView Method in not web context,
public static bool ViewExists(ControllerContext ctx, string name)
{
var result = ViewEngines.Engines.FindView(ctx, name, null);
return result.View != null;
}
I want to render view to create static files (JavaScript files rendered in Razor),
When I use this metod in web context (in controller action metod everythik is ok, but in test context I get exception
System.Web.HttpException : The application relative virtual path '~/Views/Test/New.aspx' cannot be made absolute, because the path to the application is not known.
How I would use (moq) ControllerContext in not web context to Render Razor View ?

Related

Exception Handler for normal AND ajax request for logging purpose

Can someone give me a working example of an ExceptionHandler which extends ExceptionHandlerWrapper for both normal and ajax request. I don't want to use a filter. I want all my exception handling to be in one entry place for logging purpose.
In Omnifaces we have the FullAjaxExceptionHandler but only for ajax request. How can I refactor this class in order to take into account both types of request?
In order to render the error page inside my CustomExceptionHandler, I use inside a utility method such a statement which identify the type of request (normal or ajax)
if (context.getPartialViewContext().isAjaxRequest()) {
ViewHandler viewHandler = context.getApplication().getViewHandler();
UIViewRoot viewRoot = viewHandler.createView(context, errorPageLocation);
context.setViewRoot(viewRoot);
context.getPartialViewContext().setRenderAll(true);
context.renderResponse();
} else {
NavigationHandler nav = context.getApplication().getNavigationHandler();
nav.handleNavigation(context, null, errorPageLocation);
context.renderResponse();
}
By this way I can handle both request effectively in my CustomExceptionHandler
In the Wrapper you can use, if you want to detect the type of request:
context == null || !context.getPartialViewContext().isAjaxRequest()
Also recommend you to integrate the WrapperHandler with Deltaspike Exception Control
And finally a common way to redirect (working for both types of requests):
public static void redirect(FacesContext fc, String view) {
ExternalContext ec = fc.getExternalContext();
String path = ec.encodeResourceURL(fc.getApplication().getViewHandler().getActionURL(fc, view));
try {
ec.redirect(path);
} catch(Exception e) {
throw new RuntimeException();
}
}

ASP.NET MVC 3 Dependency Injection - Controllers, Views & Action Filters

I'm trying to get dependency injection working in an ASP.NET MVC 3 application using Microsoft Unity. First i have implemented my own IDependencyResolver and activated it in my Global.asax file like so:
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
I found that i don't need to do anything else to get controller injection (via both the constructor and [Dependency] attribute) to work. With the default view engine i also found i could get the [Dependency] attribute to work in the standard views but not the Layout views. Is it possible to get this to work for the Layout Views aswell?
However i have implemented my own view engine which inherits from VirtualPathProviderViewEngine that overrides the CreateView/CreatePartialView methods and returns my own custom view (implements IView). See the Render method of the custom view below:
public void Render(ViewContext viewContext, TextWriter writer) {
var webViewPage = DependencyResolver.Current.GetService(_type) as WebViewPage;
//var webViewPage = Activator.CreateInstance(_type) as WebViewPage;
if (webViewPage == null)
throw new InvalidOperationException("Invalid view type");
webViewPage.VirtualPath = _virtualPath;
webViewPage.ViewContext = viewContext;
webViewPage.ViewData = viewContext.ViewData;
webViewPage.InitHelpers();
WebPageRenderingBase startPage = null;
if (_runViewStartPages)
startPage = StartPage.GetStartPage(webViewPage, "_ViewStart", _viewStartFileExtensions);
var pageContext = new WebPageContext(viewContext.HttpContext, webViewPage, null);
webViewPage.ExecutePageHierarchy(pageContext, writer, startPage);
}
With the commented out line i completely lost dependency injection within my views so i changed it to the line above which again works fine for the standard views but not for the Layout views. I'd appreciate it if you could show me how the above could be modified to work for the Layout views aswell?
Finally i'm trying to get action filter injection working aswell. I have found two different cases:
Apply the filter to the action via an attribute.
Defining it as a global filter, e.g.:
GlobalFilters.Filters.Add(new TestAttribute());
Neither seem to use the dependency resolver. Therefore i need to do some extra work. Please correct me if there's a better way. To enable the first scenario i did the following:
public class UnityFilterAttributeFilterProvider : FilterAttributeFilterProvider {
private IUnityContainer _container;
protected override IEnumerable<FilterAttribute> GetControllerAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {
var attributes = base.GetControllerAttributes(controllerContext, actionDescriptor);
foreach (var attribute in attributes) {
_container.BuildUp(attribute.GetType(), attribute);
}
return attributes;
}
protected override IEnumerable<FilterAttribute> GetActionAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {
var attributes = base.GetActionAttributes(controllerContext, actionDescriptor);
foreach (var attribute in attributes) {
_container.BuildUp(attribute.GetType(), attribute);
}
return attributes;
}
}
And then defined this within my Global.asax file like so:
FilterProviders.Providers.Remove(FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider));
FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));
This works fine but i was wondering if this is the correct way to do it? To resolve the second case i simply changed where i defined my global filter to the following:
GlobalFilters.Filters.Add(DependencyResolver.Current.GetService<TestAttribute>());
This again now works but is this the correct way to do it?
I'd appreciate the help. Thanks
It's been a while since I originally asked this but I thought I would share what I ended up doing.
In cases where I could not use constructor or attribute injection I solved it by using the DependencyResolver (service locator pattern). For example if I require the service IService I would simply inject it like so:
public IService Service => DependencyResolver.Current.GetService<IService>();
While some may consider this an anti-pattern I have found this performs well, leads to less problems and with new advances in C# I don't think it looks too bad.
However if you are using ASP.NET Core you should never have to use the service locator pattern as it has been rebuilt with dependency injection at the heart of it.

Adding profile values for auto-generated user

I'm creating a ASP.NET MVC 3.0 website, and have a couple of different database initializations based on whether the site is intended for development, testing, or production. I'm stuck on the testing initialization, as I'm trying to get a test user created. I can get the user to create just fine, however when I try to add some profile values, I get: System.Web.HttpException: Request is not available in this context. Is there a way to add Profile values in a situation where the request isn't going to be available?
Following code is what is being run:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
if (ApplicationServices.GetInitialCatalog() != "tasktracker")
{
Database.SetInitializer(new TaskTrackerDropCreateDatabaseIfModelChanges());
}
else
{
Database.SetInitializer(new TaskTrackerCreateDatabaseIfNotExists());
}
using (var db = new TaskTrackerContext())
{
db.Database.Initialize(false);
}
}
public class TaskTrackerDropCreateDatabaseIfModelChanges : DropCreateDatabaseIfModelChanges<TaskTrackerContext>
{
protected override void Seed(TaskTrackerContext context)
{
// Set up the membership, roles, and profile systems.
ApplicationServices.InstallServices(SqlFeatures.Membership | SqlFeatures.Profile | SqlFeatures.RoleManager);
// Create the default accounts and roles.
if (ApplicationServices.GetInitialCatalog() == "tasktracker_testing")
{
if (Membership.GetUser("testuser", false) == null)
{
Membership.CreateUser("testuser", "password", "testuser#test.com");
MembershipUser user = Membership.GetUser("testuser", false);
user.IsApproved = true;
var profile = ProfileBase.Create("testuser");
profile.SetPropertyValue("FirstName", "test");
profile.SetPropertyValue("LastName", "user");
profile.SetPropertyValue("TimeZone", "US Mountain Standard Time");
profile.Save();
}
}
}
}
Interesting question. Have you looked at using the new Universal Providers? Dunno if you will run into the same httpcontext issue but may be worth a look: http://www.hanselman.com/blog/IntroducingSystemWebProvidersASPNETUniversalProvidersForSessionMembershipRolesAndUserProfileOnSQLCompactAndSQLAzure.aspx
Did you try to do a call of "Initialize()" :
profile.Initialize(username, true)
after your create action to see if the context should be Initialized.
By using Reflector i saw the ProfileBase of Initialize (see below) creates this kind of context from the settings:
public void Initialize(string username, bool isAuthenticated)
{
if (username != null)
{
this._UserName = username.Trim();
}
else
{
this._UserName = username;
}
SettingsContext context = new SettingsContext();
context.Add("UserName", this._UserName);
context.Add("IsAuthenticated", isAuthenticated);
this._IsAuthenticated = isAuthenticated;
base.Initialize(context, s_Properties, ProfileManager.Providers);
}
It seems working here, the SettingsContext() seems taking account of my custom properties declared in the web.config.
Regards,
I come back again because the solution I added with the "Initialize()" function in fact not run really after an other test. So in fact I found a way which runs correctly.
The problem of "request is not available in this context" in application_start in your case could be due to the application mode "Integrated" which is new from II7 instead of the Classic mode.
To see a good explain you ca go on the Mike Volodarsky's blog IIS7 Integrated mode: Request is not available in this context exception in Application_Start .
I copy/paste an extract which could indicate the main reason:
" *This error is due to a design change in the IIS7 Integrated pipeline that makes the request context unavailable in Application_Start event. When using the Classic mode (the only mode when running on previous versions of IIS), the request context used to be available, even though the Application_Start event has always been intended as a global and request-agnostic event in the application lifetime. Despite this, because ASP.NET applications were always started by the first request to the app, it used to be possible to get to the request context through the static HttpContext.Current field.* "
To solve this you can use a workaround that moves your first-request initialization from Application_Start to BeginRequest and performs the request-specific initialization on the first request.
A good example of code is done in his blog :
void Application_BeginRequest(Object source, EventArgs e)
{
HttpApplication app = (HttpApplication)source;
HttpContext context = app.Context;
// Attempt to peform first request initialization
FirstRequestInitialization.Initialize(context);
}
class FirstRequestInitialization
{
private static bool s_InitializedAlready = false;
private static Object s_lock = new Object();
// Initialize only on the first request
public static void Initialize(HttpContext context)
{
if (s_InitializedAlready)
{
return;
}
lock (s_lock)
{
if (s_InitializedAlready)
{
return;
}
// Perform first-request initialization here
//
// You can use your create profile code here....
//---
s_InitializedAlready = true;
}
}
}

HttpContext in Razor Views

I tried to port some ASPX markup to Razor, but compiler threw an error.
ASPX (works fine):
<% if (node.IsAccessibleToUser(Context)) { %>
// markup
<% } %>
CSHTML (throws an error):
#if (node.IsAccessibleToUser(Context)) {
// markup
}
Argument 1: cannot convert from 'System.Web.HttpContextBase' to 'System.Web.HttpContext'
How to get reference to HttpContext in Razor view? Is it correct to use HttpContext.Current or I need to check site map node visibility in a different way?
WebViewPage.Context is HttpContextBase instance. WebViewPage.Context.ApplicationInstance.Context is HttpContext instance.
#if (node.IsAccessibleToUser(Context.ApplicationInstance.Context)) {
// markup
}
Yes, you can use HttpContext.Current. This will give you access to the request and response data.
What #Martin means is that you could write some extension methods on your Node class (whatever the type of that is), like:
public static class NodeExtensions
{
public static bool IsAccessibleToUser(this Node node)
{
// access HttpContext through HttpContext.Current here
}
}
and use it in your view like:
#if(node.IsAccessibleToUser()) {}
Thus removing the dependency on HttpContext in your view.

GWT - Handling events from underlying widgets in EntryPoint

I have searched the web for the correct answer, but I've been failing to achieve this :
In EntryPoint class, I need to manage widgets according to events that occur in nested widgets. I've cleaned of the code to focus only on what is important here.
I have built a few UiBinder widgets, for example, a Login pane where the user can enter his credentials. In my EntryPoint class, I add the widgets in the correct position.
// This is from EntryPoint class
public void onModuleLoad() {
LoginPane lp = new LoginPane();
RootPanel.get("headerRightPane").add(lp);
lp.setFocus();
// Other widgets added in same manner after this point...
}
I would like a successful login to remove the LoginPane and replace it by another widget (AccountPane) that would show the account information for the user that is logged in. I have an onClick event, in LoginPane, that sends a request to a fully functional Servlet that checks the credentials. At this exact point, if the Servlet determines that the login is indeed successful, I would like to fire a "successfulLogin" event (from LoginPane) that could notify the EntryPoint class that the LoginPane can now be replaced by the AccountPane.
// This is from LoginPane class
#UiHandler("loginButton")
void onClick(ClickEvent e) {
checkCredentials(usernameField.getText(), passwordField.getText());
}
public void checkCredentials(String username, String password) {
String usernameToServer = username;
String passwordToServer = password;
credentialsService.credentialsServer(usernameToServer, passwordToServer,
new AsyncCallback<CredentialsPaneContent>() {
public void onFailure(Throwable caught) {
answerLabel.setText(Utilities.SERVER_ERROR);
}
public void onSuccess(CredentialsPaneContent result) {
if ( result == null ) {
answerLabel.setText("Login Failed.");
} else {
// Fire event here (to be caught by EntryPoint class)
answerLabel.setText("Login Successful.");
}
}
});
}
So, the question : How should I proceed to create, fire and listen to the event from my nested widget?
Use an EventBus. Additionally, consider adopting the Model-View-Presenter pattern to keep your application maintainable as it grows:
Large scale application development and MVP, Part I
Large scale application development and MVP, Part II
GWT MVP Development with Activities and Places
Lets have an interface which is implemented by EntryPoint class,
now have a referrence of interface type which actually an object of interface.
Using this interface referrence invoke the listner(interface) mothod, which serves your purpose.

Resources