views:

610

answers:

2

I have a user control that contains a GridView. The GridView has both a HyperLinkField column and a template column that contains a HyperLink control.

The ASP.NET project is structured as follows, with the Default.aspx page in each case using the user control.

  • Application Root
    • Controls
      • UserControl with GridView
    • SystemAdminFolder
      • Default.aspx
      • Edit.aspx
    • OrganisationAdminFolder
      • Default.aspx
      • Edit.aspx
    • StandardUserFolder
      • Default.aspx
      • Edit.aspx

Note: The folders are being used to ensure the user has the correct role.

I need to be able to set the DataNavigateUrlFormatString for the HyperLinkField and the NavigateUrl for the HyperLink to resolve to the Edit.aspx page in the corresponding folder.

If I set the navigate URL to "Edit.aspx" the URL in the browser appears as 'http://Application Root/Controls/Edit.aspx' regardless of the originating directory.

I can't use the Web application root operator (~/) as the path needs to be relative to the current page, not the application root.

How can I use the same user control in multiple folders and resolve the URL to another page in the same folder?

Note: The question is strongly based off a similar question by azhar2000s on the asp.net forums that matches my problem.

+2  A: 

While typing up this question I came across one possible solution and have further modified this using feedback from @Thomas.

Changing Control.AppRelativeTemplateSourceDirectory alters the relative paths produced by the control. I've set it to a root relative virtual path for the current requests folder. Now any relative paths in the UserControl with be relative to the requested page rather than the user controls path.

//Page Load Event for the User Control
protected void Page_Load(object sender, EventArgs e)
{
    string rootPath = HttpContext.Current.Request.ApplicationPath;
    if (!rootPath.EndsWith("/"))
    {
        rootPath += "/";
    }

    Uri requestUri = HttpContext.Current.Request.Url;
    string folderPath = requestUri.AbsolutePath.Remove(0, rootPath.Length);
    string lastSegment = requestUri.Segments[requestUri.Segments.Length - 1];
    folderPath = folderPath.Remove(folderPath.LastIndexOf(lastSegment));

    AppRelativeTemplateSourceDirectory = "~/" + folderPath;
}
Daniel Ballinger
A: 

I would set it in the Load event of the grid or the page like so:

var hyperlinkColumn = this.GridView1.Columns[0] as HyperLinkColumn;
hyperlinkColumn.DataNavigateUrlFormatString = "~/SystemAdminFolder/{0}";

This structure presumes that the Url should be different per row based on the DataNavigateUrlField. If it should be the same url for all rows, then you can just set the NavigateUrl property at Load. Obviously, you would set a different folder based on the user's role.

ADDITION Given what you have mentioned in your problem in comments, what I suggest is storing the Role-Folder relationship somewhere. You have a number of choices:

  1. Simply store magically named keys in appSettings (Role_SystemAdministrators, Role_OrganizationAdministrators, etc.) with the name of the folder to which they should be directed. The advantage of this approach is that it is simple. The disadvantage is that the data must entered properly, there is nothing to stop someone from accidentally mapping a role to two folders and when a role is added it must be updated in one more place.

  2. Create a custom ConfigSection to store the relationship. The advantage is that you can ensure that each role is only listed once. The disadvantage is that it is extra code you have to write and when a role is added you still have to add something in another place.

  3. Read the location tags out of the config file. The advantage is that you can avoid having to write a value in more than one place. The disadvantage is that doing this will be a chore. You'd have to find the first tag associated with the given folder on which the current user was given permission.

  4. Read the values out of the database. The advantage is that you can easily write a management screen to update the values. The disadvantage is when a role is added you need to add something to a completely different location of the application.

You would still set folder permissions as you are doing now. However, once you have this relationship stored, you can redirect the person to the appropriate folder without having write custom forking code.

Thomas
Thanks, this is one option for changing that path based on the folder. In an ideal world the user control wouldn't need code specific to the folder it is being used in (which my solution doesn't fully address either). That is, I'd like to be able to drop the control in any arbitrary page and always have the link point to the Edit.aspx page in the same folder as the containing page.
Daniel Ballinger
@Daniel Ballinger - Are the pages for each role significantly different? I.e., couldn't you simply fork the functionality based on role within a single page?
Thomas
@Thomas - Sure, I could rework the separate pages into one. I'd lose the advantage of using separate folders which enforce the access restrictions. I guess what I'm really looking for with this question is how to make relative URL paths in a user control with respect to the pages rather than the user controls path. The paths from the user control should be agnostic to the page the control is used on.
Daniel Ballinger
@Daniel Ballinger - Ok. I did not realize that was the root problem. I've updated my post to provide a possible answer to this part of the problem.
Thomas