PortalFramework does not use virtual (mapped) URL's

Last post 01-11-2005 3:10 PM by sschack. 11 replies.

Sort Posts:

  • PortalFramework does not use virtual (mapped) URL's

    02-13-2004, 2:54 PM
    • Member
      355 point Member
    • Dr.NETjes
    • Member since 02-13-2004, 2:39 PM
    • Posts 71

    The personalization in the Portal framework uses URL's to distinguish each page. I.e. if I look in the ASPNetDB, I can see the aspnet_Urls table getting filled with new URL's after I create new pages and call them in my browser.
    However, when I use UrlMapping (the default Whidbey one, or in my own IHttpModule), the Portal framework doesn't see this as a new page.

    For example: I've mapped the virtual page 'MyVirtualPage.aspx' to the real url 'Default.aspx?page=23'. I was now hoping that also the virtual page 'MyVirtualPage.aspx' would be automatically added to the aspnet_Urls table by the Portal Framework, so I could create virtual pages containing their own webparts.

    Is this going to be changed in the beta of Whidbey? Or is this by design?

    thanks,
    Dion

  • Re: PortalFramework does not use virtual (mapped) URL's

    12-11-2004, 10:04 AM
    • Member
      355 point Member
    • Dr.NETjes
    • Member since 02-13-2004, 2:39 PM
    • Posts 71

    I've re-tested this on the Beta1 release, and this still doesn't work like I hoped it would :(
    Using urlmapping, a virtual aspx page gets redirect to the mapped page (showing the url of the mapped page in the address-bar of IE.

    I'm still hoping that urlmapping and the portal framework can work together (so I n create virtual pages managed by the portal framework).

    --Dion
  • Re: PortalFramework does not use virtual (mapped) URL's

    12-11-2004, 11:14 AM
    • All-Star
      29,634 point All-Star
    • Fredrik N
    • Member since 06-22-2002, 5:03 AM
    • Sweden
    • Posts 5,334
    • TrustedFriends-MVPs
    You can report this to the MSDN Feedback center.
    /Fredrik Normén - fredrikn @ twitter

    ASPInsider

    Microsoft MVP, MCSD, MCAD, MCT

    ASPInsiders
    My Blog
  • Re: PortalFramework does not use virtual (mapped) URL's

    12-24-2004, 6:44 PM
    • Contributor
      3,349 point Contributor
    • wyx2000
    • Member since 11-25-2002, 11:43 AM
    • Posts 808
    well, this way may be perferred by some sites. and it is more reasonable. when you want to have different content on different url, you should have two different pages, what is the point to map there?

    but if you really need do that, I think you could try the context.rewritepath, the provider use the current url to store the setting, in the page_load of your default.aspx?pageid=??? , you could rewrite the path to the mapped so the provider will use that instead. Or you could write your own provider to do that.
  • Re: PortalFramework does not use virtual (mapped) URL's

    01-06-2005, 5:07 PM
    • Contributor
      3,067 point Contributor
    • sschack
    • Member since 09-16-2003, 12:06 PM
    • Posts 613
    • AspNetTeam
      Moderator
    The PersonalizationProvider base class defines the following methods as protected virtual: LoadPersonalizationBlob, SavePersonalizationBlob, and ResetPersonalizationBlob. When UrlMapping is used, the value of Request.RawUrl will reflect the original and unmapped Url.

    With these two technical points in mind, the solution to web parts personalization for virtual URLs in Whidbey is:
    1. Derive from the SqlPersonalizationProvider, and override the methods listed above.
    2. In the overrides, determine the virtual page name using Request.RawUrl.
    3. Call the base class methods, but pass in a different value for the path parameter.
    4. In web.config, configure your custom personalization provider and have webparts personalization use your custom provider instead.

    The net effect of this will be that your custom provider will intercept each load/save/reset request from web parts, and will substitute the virtual page name instead.

    In a future release of ASP.NET we will look at making this scenario more "automatic". We may bake in support for handling remapped URLs, or we may raise an event out of the provider that allows a developer to change the path parameter just prior to calling into the database.
    -Stefan
    ----------------------------------------------------------
    This posting is provided "AS IS" with no warranties, and confers no rights.
  • Re: PortalFramework does not use virtual (mapped) URL's

    01-08-2005, 11:17 AM
    • All-Star
      29,634 point All-Star
    • Fredrik N
    • Member since 06-22-2002, 5:03 AM
    • Sweden
    • Posts 5,334
    • TrustedFriends-MVPs
    Stefan:

    There are only two things you forgot to mention ;) The SqlPeronslaizationProvider is sealed in the latest CTP build of ASP.Net. Hopefully this will not be sealed when beta 2 is released!?

    A new custom WebPartPersonalization class must also be created where the HasPersonalizationState method must be override and also pass the Request.RawUrl to the providers GetCountOfState method.

    Because there must be a new WebpartPersonalization class, there must also be a new custom WebPartManager class where the CreatePersonalization method is override and returns the new custom WebPartPersonalization class:

    Custom WebPartManager:


    public class MyWebPartManager : WebPartManager
    {
    public MyWebPartManager()
    {
    }

    protected override WebPartPersonalization CreatePersonalization()
    {
    return new Nsquared2WebPartPersonalization(this);
    }
    }


    Custom WebPartPersonalization:


    public class Nsquared2WebPartPersonalization : WebPartPersonalization
    {
    private PersonalizationProvider _provider;


    public Nsquared2WebPartPersonalization(WebPartManager owner) : base(owner)
    {
    }


    public override bool HasPersonalizationState
    {
    get
    {
    if (this._provider == null)
    throw new InvalidOperationException("Can't use the WebPartPersonalization's HasPersonalizationState before Page_Init");

    if (this.WebPartManager.Page == null)
    throw new InvalidOperationException("The WebPartManager.Page property can not be null");

    HttpRequest request = this.WebPartManager.Page.Request;
    if (request == null)
    throw new InvalidOperationException("The WebPartManager.Page.Request property can not be null");

    PersonalizationStateQuery query = new PersonalizationStateQuery();

    query.PathToMatch = request.RawUrl;

    if ((this.Scope == PersonalizationScope.User) && request.IsAuthenticated)
    query.UsernameToMatch = this.WebPartManager.Page.User.Identity.Name;

    return (this._provider.GetCountOfState(this.Scope, query) > 0);
    }
    }


    private void DeterminePersonalizationProvider()
    {
    if (string.IsNullOrEmpty(this.ProviderName))
    {
    this._provider = PersonalizationAdministration.Provider;
    }
    else
    {
    PersonalizationProvider provider = PersonalizationAdministration.Providers[this.ProviderName];
    if (provider == null)
    {
    throw new ProviderException(string.Format("Can't found provider '{0}'", this.ProviderName));
    }
    this._provider = provider;
    }
    }


    protected override PersonalizationScope Load()
    {
    if (!this.Enabled)
    throw new InvalidOperationException("Personalization not enabled");

    this.DeterminePersonalizationProvider();

    return base.Load();
    }

    ....
    }


    Custom SqlPersonalizationProvider (When it's not sealed ;) )


    public class Nsquared2SqlPersonalizationProvider : SqlPersonalizationProvider
    {

    private string GetPath(WebPartManager webPartManager)
    {
    if (webPartManager == null)
    throw new ArgumentNullException("webPartManager");

    if (webPartManager.Page == null)
    throw new ArgumentException("The webPartManager's Page property can not be Null");

    HttpRequest request = webPartManager.Page.Request;
    if (request == null)
    throw new ArgumentException("The webPartManager's Page.Request property can not be Null");

    path = request.RawUrl;
    }


    protected override void LoadPersonalizationBlobs(WebPartManager webPartManager, string path, string userName, ref byte[] sharedDataBlob, ref byte[] userDataBlob)
    {
    base.LoadPersonalizationBlobs(webPartManager, this.GetPath(webPartManager), userName, sharedDataBlob, userDataBlob);
    }

    protected override void ResetPersonalizationBlob(WebPartManager webPartManager, string path, string userName)
    {
    base.ResetPersonalizationBlob(webPartManager, this.GetPath(webPartManager), userName, sharedDataBlob, userDataBlob);
    }

    protected override void SavePersonalizationBlob(WebPartManager webPartManager, string path, string userName, byte[] dataBlob)
    {
    base.ResetPersonalizationBlob(webPartManager, this.GetPath(webPartManager), userName, sharedDataBlob, userDataBlob);
    }
    }

    /Fredrik Normén - fredrikn @ twitter

    ASPInsider

    Microsoft MVP, MCSD, MCAD, MCT

    ASPInsiders
    My Blog
  • Re: PortalFramework does not use virtual (mapped) URL's

    01-11-2005, 1:27 PM
    • Contributor
      3,067 point Contributor
    • sschack
    • Member since 09-16-2003, 12:06 PM
    • Posts 613
    • AspNetTeam
      Moderator
    The SqlPersonalizationProvider will be unsealed in Beta 2.

    Overriding GetCountOfState is not strictly necessary. Since WebPartPageMenu was cut, the GetCountOfState method is not called by the Web Parts code. The earlier question about handling remapped Urls can still be solved with a custom provider. Extending WebPartPersonalization is probably a bit of overkill for this scenario.

    If you author your own equivalent to WebPartPageMenu, and you need GetCountOfState to functionpropertly, GetCountOfState can also be overridden with a derived provider. The value of query.PathToMatch can be modified to reflect the original friendly URL prior to calling base.GetCountOfState(...).

    Note though that you should probably check and see if the current request is running for a page with an active WebPartManager. The GetCountOfState method is considered an administrative method and thus can be called from admin pages. In the administration scenario, the provider is being called outside the context of a web part page.

    -Stefan
    ----------------------------------------------------------
    This posting is provided "AS IS" with no warranties, and confers no rights.
  • Re: PortalFramework does not use virtual (mapped) URL's

    01-11-2005, 2:02 PM
    • All-Star
      29,634 point All-Star
    • Fredrik N
    • Member since 06-22-2002, 5:03 AM
    • Sweden
    • Posts 5,334
    • TrustedFriends-MVPs
    Stefan:

    There was a question, not so long ago within this forum when a person wanted to use the HasPersonalizationState to check if the personalization information for the current logged in user and page has been saved. For that reason I think it could be good to let others know that they need to override the HasPersonalizationState method to make sure it will work for the current page. I don't think the provider's GetCountOfState should internally replace the queries PathToMatch by the raw Url, by doing that, no one could use the GetCountState to get the number of state based on their own query.

    My conclusion was to make sure all methods that uses the personalization provider, should work as normal, even if the raw Url is used in instead of the current executed page's Url.
    /Fredrik Normén - fredrikn @ twitter

    ASPInsider

    Microsoft MVP, MCSD, MCAD, MCT

    ASPInsiders
    My Blog
  • Re: PortalFramework does not use virtual (mapped) URL's

    01-11-2005, 2:09 PM
    • Contributor
      3,067 point Contributor
    • sschack
    • Member since 09-16-2003, 12:06 PM
    • Posts 613
    • AspNetTeam
      Moderator
    GetCountOfState is sort of the odd man out since it does not have a WebPartManager in the parameter list - LoadPersonalizationBlobs, SavePersonalizationBlob and ResetPersonalizationBlob all have a WebPartManager in their parameter list. As a result, these three methods are guaranteed to only be called by the web parts infrastructure and thus overriding them in a derived provider is a simple solution.

    I suspect most developers are not going to be worried about using GetCountOfState in pure adminstrative scenarios - in which case overriding GetCountOfState in a derived provider and changing the path is simple solution to the problem of using virtual URLs with web parts.

    The issue with overriding WebPartPersonalization is that it leads to overriding WebPartManager. We try to avoid this type of guidance because it forces developers down the road of dealing with internals of web parts.
    -Stefan
    ----------------------------------------------------------
    This posting is provided "AS IS" with no warranties, and confers no rights.
  • Re: PortalFramework does not use virtual (mapped) URL's

    01-11-2005, 2:33 PM
    • All-Star
      29,634 point All-Star
    • Fredrik N
    • Member since 06-22-2002, 5:03 AM
    • Sweden
    • Posts 5,334
    • TrustedFriends-MVPs
    Stefan:

    I can see your point and I agree. But if the solution of using a raw Url, should work. The following methods most be overriden: GetCountOfState, SavePersonalizationBlob, LoadPersonaizationBlobs and ResetPersonalizationBlob. If we don't override the GetCountOfState and make sure it replaces its path argument’s value with the raw Url, the HasPersonalizationState method will not work properly with the solution.

    I did actually a post on my blog about this:

    Make the WebPart personalize a page on its raw Url.
    /Fredrik Normén - fredrikn @ twitter

    ASPInsider

    Microsoft MVP, MCSD, MCAD, MCT

    ASPInsiders
    My Blog
  • Re: PortalFramework does not use virtual (mapped) URL's

    01-11-2005, 3:10 PM
    • Contributor
      3,067 point Contributor
    • sschack
    • Member since 09-16-2003, 12:06 PM
    • Posts 613
    • AspNetTeam
      Moderator
    Agreed. I was pointing out that the Whidbey web parts implementation no longer checks WebPartPersonalization.HasPersonalizationState, so a developer could bypass the issue.

    In the provider, the hacky workaround to determine if the path needs to be modified would look like:

    if (HttpContext.Current.Handler is Page)
    {
    Page p = (Page)HttpContext.Current.Handler;
    WebPartManager wpm = WebPartManager.GetCurrentWebPartManager(p);
    if (wpm != null)
    {
    //At this point you know you are running on a page with a web part manager
    //Of course if your administrative app also uses web parts, you would need more logic
    //to differentiate between a runtime web parts page and an admin page.
    query.PathToMatch = HttpContext.Current.Request.RawUrl;
    base.GetCountOfState(scope, query);
    }
    }
    else
    {
    base.GetCountOfState(scope,query);
    }
    -Stefan
    ----------------------------------------------------------
    This posting is provided "AS IS" with no warranties, and confers no rights.
Page 1 of 1 (11 items)