RequestContext in composite control - asp.net

I'm trying to access the route data within a composite control to change the directory lookup for images based on the section the user is browsing to.
e.g: http://www.mysite.com/photos/palmtrees
In this cause, {palmtrees} = {id} and I'd like to access this within a composite control.
I've read up about similar requirements but cannot seem to the get RequestContext to return anything but null?
// this.Context = HttpContext.Current;
HttpContextBase htb = new HttpContextWrapper(this.Context);
RequestContext rc = new RequestContext(htb, RouteTable.Routes.GetRouteData(htb));
// rc -> is always NULL?
Is there an easier way to get the RouteData within my control?

Jumping between routes was outside of the route context, meaning that RouteData was never available.
Ensured that when a user clicks on a button to take them to /photo/{id} the context of the route was activated.
Not using MVC, this is a Web Form project.

Related

Are there any packages etc implementing dynamic role controller access for MVC3?

I have statically allowed access to controllers/action methods using the standard Authorize attribute with roles. I am using the default ASP.Net Membership Provider.
One of our clients wants finer grained access control. They would like to be able to dynamically assign which roles can access which controllers/actions etc. I've seen answers saying implement a CustomAuthorize Attribute.
Just wondered if there were any toolkits etc to this. It seems a reasonably standard feature. I guess something like this http://kbochevski.blogspot.com/2009/11/mvc-custom-authorization.html
Try a custom attribute like this:
public class DynamicAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var controllerName = httpContext.Request.RequestContext.RouteData.Values["controller"];
var actionName = httpContext.Request.RequestContext.RouteData.Values["action"];
// Get this string (roles) from a database or somewhere dynamic using the controllerName and actionName
Roles = "Role1,Role2,Role3"; // i.e. GetRolesFromDatabase(controllerName, actionName);
return base.AuthorizeCore(httpContext);
}
}
Just put this attribute on any action method that requires authorization and do a look up in a database with the controller name and action name to get the required roles.
Hope this helps,
Mark

How to access asp.net mvc route values in GetVaryByCustomString?

I'm running an asp.net mvc 2 site under .NET 3.5 and I'd like to have access to routing values in my GetVaryByCustomString handler in Global.asax. I'm unclear how (if at all) to access specific route values given the HttpContext passed to the function.
For reference, here is the signature of GetVaryByCustomString
public override string GetVaryByCustomString(HttpContext context, string custom)
{
// how do I get at route values here from context?
}
Can someone point me in the right direction?
For anybody trying to make this work on ASP.NET MVC 4.0 onward, this is the correct way.
HttpContextBase currentContext = new HttpContextWrapper(context);
RouteData routeData = RouteTable.Routes.GetRouteData(currentContext);
This is a bit of hack, but this is the only solution at this moment, because caching validation is performed before routing, so route data is not available.
var routeData = ((MvcHandler)httpContext.Handler).RequestContext.RouteData;
var routeValues = routeData.Values;
var matchedRouteBase = routeData.Route;
var matchedRoute = matchedRouteBase as Route
Here's an easier way
httpContext.Current.Request.RequestContext.RouteData

How to create singleton Page in asp.net

We can use a class implement IHttpHandlerFactory to override or intercept the create progress of Page's instance
In a word we can use:
PageHandlerFactory factory = (PageHandlerFactory)Activator.CreateInstance(typeof(PageHandlerFactory), true);
IHttpHandler handler = factory.GetHandler(context, requestType, url, pathTranslated);
return handler;
to create new instance of asp.net page object.
But you know, the page is not in persistence
If you save the object in applicationstate or session, when next request, you can get the page,but you will find the Application(HttpApplication) in "Page.Context" is null.
In that, the page visit will fail and it cannot be a singleton one.
How to set the httpApplication?
I don't understand all of your question, but I guess you are looking for HttpContext.Current.Application
Use that instead of Page.Context.Application.
I think that you need to call the internal protected FrameworkInitialize() function after the page has been constructed.

ASP.NET SQL Profile Provider - Does the ProfileBase.Create() method hit DB?

I am working with the SQLMemebershipProvider and using Profiles. I have a custom class called UserProfile that inherits from the ProfileBase class and I use this to set custom properties like "FullName". I am wanting to loop through all the users in the database and get access to their profile properties. On each iteration I am calling ProfileBase.Create() to get a new profile and then access the properties.
It looks to me like every time ProfileBase.Create() is called it hits my SQL database. But I am just looking for confirmation of this. So, does anyone know if this does in fact hit the DB each time?
And better yet, does anyone have a better solution of how I could make one call to the DB to get all users with their custom profile attributes?
I know I could write my own stored proc, but I am wondering if there is a way built in to the Membership Provider.
Mike, I believe what you observed is true. I am working with a ProfileProvider that uses Azure TableStorage as data store. I wanted to get a list of user profiles from database and merge them with information from membership provider.
It took some time until I realized that calling ProfileBase.Create() with a username as argument performs a lookup against TableStorage and actually retrieves the data associated with that username. As far as I'm concerned, calling this method Create() is misleading, I would expect Load() or Get().
Currently my code looks like this:
public IEnumerable<AggregatedUser> GetAllAggregatedUsers()
{
ProfileInfoCollection allProfiles = this.GetAllUsersCore(
ProfileManager.GetAllProfiles(ProfileAuthenticationOption.All)
);
//AggregatedUser is simply a custom Class that holds all the properties (Email, FirstName) that are being used
var allUsers = new List<AggregatedUser>();
AggregatedUser currentUser = null;
MembershipUser currentMember = null;
foreach (ProfileInfo profile in allProfiles)
{
currentUser = null;
// Fetch profile information from profile store
ProfileBase webProfile = ProfileBase.Create(profile.UserName);
// Fetch core information from membership store
currentMember = Membership.FindUsersByName(profile.UserName)[profile.UserName];
if (currentMember == null)
continue;
currentUser = new AggregatedUser();
currentUser.Email = currentMember.Email;
currentUser.FirstName = GetStringValue(webProfile, "FirstName");
currentUser.LastName = GetStringValue(webProfile, "LastName");
currentUser.Roles = Roles.GetRolesForUser(profile.UserName);
currentUser.Username = profile.UserName;
allUsers.Add(currentUser);
}
return allUsers;
}
private String GetStringValue(ProfileBase profile, String valueName)
{
if (profile == null)
return String.Empty;
var propValue = profile.PropertyValues[valueName];
if (propValue == null)
return String.Empty;
return propValue.PropertyValue as String;
}
Is there a better (more straightforward, more performant) way to
retrieve all the custom profile information from profile provider and
merge them with membership provider info to show them e.g. in an administrator page?
I have had a look at Web Profile Builder but IMO this only provides design-time intellisense for custom profile properties by generating a proxy class.
You don't persist to the database until you call Save:
The Save method writes modified
profile property values to the data
source. The profile provider can
reduce the amount of activity at the
data source by performing updates only
when the IsDirty property is set to
true. This is the case for the default
SqlProfileProvider.

Access/use the same object during a request - asp.net

i have a HttpModule that creates an CommunityPrincipal (implements IPrincipal interface) object on every request. I want to somehow store the object for every request soo i can get it whenever i need it without having to do a cast or create it again.
Basically i want to mimic the way the FormsAuthenticationModule works.
It assigns the HttpContext.User property an object which implements the IPrincipal interface, on every request.
I somehow want to be able to call etc. HttpContext.MySpecialUser (or MySpecialContext.MySpecialUser - could create static class) which will return my object (the specific type).
I could use a extension method but i dont know how to store the object so it can be accessed during the request.
How can this be achieved ?
Please notice i want to store it as the specific type (CommunityPrincipal - not just as an object).
It should of course only be available for the current request being processed and not shared with all other threads/requests.
Right now i assign my CommunityPrincipal object to the HttpContext.User in the HttpModule, but it requires me to do a cast everytime i need to use properties on the CommunityPrincipal object which isnt defined in the IPrincipal interface.
I'd recommend you stay away from coupling your data to the thread itself. You have no control over how asp.net uses threads now or in the future.
The data is very much tied to the request context so it should be defined, live, and die along with the context. That is just the right place to put it, and instantiating the object in an HttpModule is also appropriate.
The cast really shouldn't be much of a problem, but if you want to get away from that I'd highly recommend an extension method for HttpContext for this... this is exactly the kind of situation that extension methods are designed to handle.
Here is how I'd implement it:
Create a static class to put the extension method:
public static class ContextExtensions
{
public static CommunityPrinciple GetCommunityPrinciple(this HttpContext context)
{
if(HttpContext.Current.Items["CommunityPrinciple"] != null)
{
return HttpContext.Current.Items["CommunityPrinciple"] as CommunityPrinciple;
}
}
}
In your HttpModule just put the principal into the context items collection like:
HttpContext.Current.Items.Add("CommunityPrincipal", MyCommunityPrincipal);
This keeps the regular context's user property in the natural state so that 3rd party code, framework code, and anything else you write isn't at risk from you having tampered with the normal IPrincipal stroed there. The instance exists only during the user's request for which it is valid. And best of all, the method is available to code as if it were just any regular HttpContext member.... and no cast needed.
Assigning your custom principal to Context.User is correct. Hopefully you're doing it in Application_AuthenticateRequest.
Coming to your question, do you only access the user object from ASPX pages? If so you could implement a custom base page that contains the cast for you.
public class CommunityBasePage : Page
{
new CommunityPrincipal User
{
get { return base.User as CommunityPrincipal; }
}
}
Then make your pages inherit from CommunityBasePage and you'll be able to get to all your properties from this.User.
Since you already storing the object in the HttpContext.User property all you really need to acheive you goal is a Static method that acheives your goal:-
public static class MySpecialContext
{
public static CommunityPrinciple Community
{
get
{
return (CommunityPrinciple)HttpContext.Current.User;
}
}
}
Now you can get the CommunityPrinciple as:-
var x = MySpecialContext.Community;
However it seems a lot of effort to got to avoid:-
var x = (CommunityPrinciple)Context.User;
An alternative would be an Extension method on HttpContext:-
public static class HttpContextExtensions
{
public static CommunityPrinciple GetCommunity(this HttpContext o)
{
return (CommunityPrinciple)o.User;
}
}
The use it:-
var x = Context.GetCommunity();
That's quite tidy but will require you to remember to include the namespace where the extensions class is defined in the using list in each file the needs it.
Edit:
Lets assume for the moment that you have some really good reason why even a cast performed inside called code as above is still unacceptable (BTW, I'd be really interested to understand what circumstance leads you to this conclusion).
Yet another alternative is a ThreadStatic field:-
public class MyModule : IHttpModule
{
[ThreadStatic]
private static CommunityPrinciple _threadCommunity;
public static CommunityPrinciple Community
{
get
{
return _threadCommunity;
}
}
// Place here your original module code but instead of (or as well as) assigning
// the Context.User store in _threadCommunity.
// Also at the appropriate point in the request lifecyle null the _threadCommunity
}
A field decorated with [ThreadStatic] will have one instance of storage per thread. Hence multiple threads can modify and read _threadCommunity but each will operate on their specific instance of the field.

Resources