When executing a link to an existing detailview item from a non XAF web page or email the Login.aspx page is shown and the user is able to login but the page specified in the original link is ignored and the user is directed to the default navigation item.
I am using these hyperlinks to send action items to users via email. What I need is for the user to be able to click the link and go to the correct detail item even if they are not currently logged in. If they are not logged in then they of course will have to provide their user name and password. I just want them to go to the detail record after the login page.
I have verified that the ReturnUrl is correct in the querystring for login.aspx. For some reason it just ignores it.
Please see the steps to reproduce.
Steps to Reproduce:
Open an XAF web application and open any item in the detailview.
Copy the entire URL from the address bar. It should look something like: http://localhost:2064/default.aspx?#ShortcutViewID=Account_DetailView&ShortcutObjectKey=bf662eec-db6c-41cb-8c18-7d24589c5f59&ShortcutObjectClassName=IXCRM.Module.BusinessObjects.Entity.Account&Shortcutmode=View
Close the browser.
Open a new instance of the browser and paste in the saved url.
Actual Results:
The login page is displayed.
After logging in the default navigation item or first navigation item if no default is set will be displayed.
Expected Results:
The login page is displayed.
After logging in the Detailview for the full URL which was pasted into the address bar will be shown. In this exampel I would expect to see the Accounts item in a view only detail view.
How to open a View specified in an external link after logging in to a Web application with the security system enabled?
Answers approved by DevExpress Support
Hello,
We've simplified URL customization for ListViews and DetailViews in Web apps with the new RouteManager API in v19.1. For example, you can now customize URLs to match the following highly requested format:
BEFORE:
*/Default.aspx#ViewID=Contact_ListView
*/Default.aspx#ViewID=Contact_DetailView&ObjectKey=ContactId
AFTER:
*/Contact_ListView/
*/Contact_DetailView/ContactId/
To make sure that our future implementation meets your business requirements, we would greatly appreciate it if you test our early access preview version. Read this knowledge base article to learn more about this new capability.
Thank you for your time and cooperation,
Arkady
Other Answers
All of this back and forth inspired me to look into this further and I have found a solution to the issue that maintains the .Net FormsAuthentication security.
To allow redirect to a link make the following changes:
-
In your model for your web app change the Logon Action IsPostBackRequired value to TRUE
-
Add a hidden html element to your login.aspx file. Make sure to set runat="server" for the element.
-
You will need to change the format of the shortcut. The XAF shortcuts have all sorts of Querystring delimiters that the .Net security system does not like. In my case I took the shortcut and made the following replacements:
Replace # with _H_
Replace = with _E_
Replace & with _A_
The original XAF url looked like this:
Default.aspx#ShortcutViewID=ActivityCode_DetailView&ShortcutObjectKey=3da811aa-1391-4121-a44e-881749a0bf67&ShortcutObjectClassName=ConnHall.Module.BusinessObjects.MasterFiles.ActivityCode&Shortcutmode=View
After my replacements my Url would look like this:
Default.aspx_H_ShortcutViewID_E_ActivityCode_DetailView_A_ShortcutObjectKey_E_3da811aa-1391-4121-a44e-881749a0bf67_A_ShortcutObjectClassName_E_ConnHall.Module.BusinessObjects.MasterFiles.ActivityCode_A_Shortcutmode_E_View
-
In order to use the changes you will need to point all of your shortcuts to the login.aspx file and add a value for the querystring Request variable. My shortcut looks like this:
http://localhost/web/Login.aspx?Request=Default.aspx_H_ShortcutViewID_E_ActivityCode_DetailView_A_ShortcutObjectKey_E_3da811aa-1391-4121-a44e-881749a0bf67_A_ShortcutObjectClassName_E_ConnHall.Module.BusinessObjects.MasterFiles.ActivityCode_A_Shortcutmode_E_View -
Change the code in your Login.aspx to the following:
C#protected void Page_Load(object sender, EventArgs e)
{
// Only fire the custom logic if the request value is set
if (Request.QueryString["Request"] != null)
{
if (WebApplication.Instance.IsLoggedOn)
{
// The user is already logged on so go right to the page
string redirect = Request.QueryString["Request"];
// Make the replacements for the character changes we made to the shortcut
redirect = redirect.Replace("_H_", "#");
redirect = redirect.Replace("_E_", "=");
redirect = redirect.Replace("_A_", "&");
Response.Redirect(redirect);
}
else
{
//Store the value in the hidden field for use after the postback
string redirect = Request.QueryString["Request"];
Hidden1.Value = redirect;
WebApplication.Instance.CreateLogonControls(this);
// Attach to the logon event so we can redirect after the user is logged in
WebApplication.Instance.LoggedOn += new EventHandler<DevExpress.ExpressApp.LogonEventArgs>(Instance_LoggedOn);
}
}
else
WebApplication.Instance.CreateLogonControls(this);
}
void Instance_LoggedOn(object sender, DevExpress.ExpressApp.LogonEventArgs e)
{
if (Hidden1.Value != null)
{
//Get the value from the hidden field and redirect to the shortcut page
string redirect = Hidden1.Value;
redirect = redirect.Replace("_H_", "#");
redirect = redirect.Replace("_E_", "=");
redirect = redirect.Replace("_A_", "&");
WebApplication.Redirect(redirect);
}
else
{
WebApplication.Redirect("Default.aspx");
}
}
And that is it.
Obviously this example is down and dirty and I would most likely fine tune the replacements to shorten up the shortcut by replacing for example &Shortcut with _A_ or something like that but you get the idea.
Also you will want to create a CustomFunctionFormatter for creating the shortcuts in HTML reports.
Maybe the DX folks can take a look at this and see if they see any pitfalls or issues but it seems to work fine on 2012 vol 1.
@John: We do not currently have a ready sample for the latest version, but we will consider creating it. For now, please create a new ticket and attach your current project where you tried to implement a solution according to Michael's instructions above. We will be more than happy to look at what was wrong there.
Hi Dennis
I'm currently on version 18.1.6. Any solution that works works with this version? I have tried so many examples but they all seem to be from 4 to 7 years back and are not working on 18.1.6. Please kindly assist
@Samuel Gwanzura: The "Current solution" section under Michael's answer describes the actual solution. Let us know if you experience any difficulties with it.
Hi Mark,
XAF URLs contain a ViewShortcut part after the "#" delimiter. We use "#" instead of "?" in the new AJAX implementation to avoid sending unnecessary requests to the server. If an XAF application uses a security system, the shortcut part is cleared by ASP.NET because of a security policy, and the browser is always navigated to the default view.
Current solution
You can consider the following simple solution, which worked fine in many internal tests:
- In the Solution Explorer, right-click the YourSolutionName.Web/Login.aspx file and invoke the View Markup command from the context menu.
- Paste the <script/> element with the JavaScript code below before the </body> element, as follows:
<body class="Dialog">
<div id="PageContent" class="PageContent DialogPageContent">
<form id="form1" runat="server">
<cc4:ASPxProgressControl ID="ProgressControl" runat="server" />
<div id="Content" runat="server" />
</form>
</div>
<%--This part is added.--%>
<script type="text/javascript">
//<![CDATA[
function encodeLocationHash() {
var search = window.location.search;
if (search && search.indexOf('ReturnUrl=') > -1) {
var hash = window.location.hash;
if (hash && hash.length > 1) {
var newUrl = window.location.href.replace(hash, '');
var paramPosition = newUrl.search('&');
if (paramPosition > 0) {
newUrl = newUrl.substring(0, paramPosition) + encodeURIComponent(hash) + newUrl.substring(paramPosition);
}
else {
newUrl += encodeURIComponent(hash);
}
window.location.replace(newUrl);
}
}
}
attachWindowEvent('load', encodeLocationHash);
//]]>
</script>
</body>
Refer to the http://dennisgaravsky.blogspot.com/2015/05/redirecting-from-external-hyperlink-to.html blog post for more details.
Previous solutions
As a solution, you can declare a custom HTTP handler as follows:
C#public class ReturnUrlHttpHandler : IHttpHandler, IRequiresSessionState {
private IHttpHandler m_actualHandler;
public IHttpHandler ActualHandler {
get {
return m_actualHandler;
}
}
public bool IsReusable {
get {
return false;
}
}
public void ProcessRequest(HttpContext context) {
TemplateContext templateContext__1 = WebApplication.Instance.RequestManager.GetTemplateContext();
WebApplication.CurrentRequestTemplateType = WebApplication.Instance.RequestManager.GetTemplateType();
if (templateContext__1 != TemplateContext.Undefined) {
if (!WebApplication.Instance.IsLoggedOn && templateContext__1 != TemplateContext.LogonWindow) {
Page redirectTemplate = new Page();
String script = RenderUtils.GetScriptHtml(String.Format("window.location.href='{0}' + '?ReturnUrl=' + encodeURIComponent(window.location.pathname + window.location.hash);", WebApplication.LogonPage));
redirectTemplate.Controls.Add(new LiteralControl(script));
redirectTemplate.ProcessRequest(context);
return;
}
IFrameTemplate template = WebApplication.Instance.CreateTemplate(templateContext__1);
Page page = (Page)template;
m_actualHandler = page;
((IHttpHandler)template).ProcessRequest(context);
} else {
IHttpHandler unknownPage = (IHttpHandler)System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath(context.Request.Path, typeof(Page));
m_actualHandler = unknownPage;
unknownPage.ProcessRequest(context);
}
}
}
See a VB example in the Using WebWindowTemplateHttpHandler in v14.1 as per B222208 ticket.
Then, attach this handler to your application by adding the following entry to Web.config:
XML<httpHandlers>
<add verb="*" path="*.aspx" type="MainDemo.Web.ReturnUrlHttpHandler" validate="false" />
...
</httpHandlers>
Finally, modify the <system.web> <authorization> node in Web.config as follows:
C#<authorization>
<!--<deny users="?"/>-->
<allow users="*" />
</authorization>
After that, when a non-logged-in user opens your application by a certain URL, he or she will be redirected to this URL after logging in. Take special note that the last configuration code will disable the default ASP.NET security (learn more…) that caused the original behavior. So, you will have to additionally ensure that no sensitive resources are available in your web application for free access (as in theory it is possible to pick or guess a URL for a resource).
hey Dennis, thanks for getting this on the ToDo list… this is important for many of us web-oriented folks. Prior to official implementation, if you have time, would you mind upgrading the sample project you attached, to current standards. This way each of us won't have to… cheers, drew…
Guys, please try a simpler solution described in the Redirecting from an external hyperlink to a View in an XAF Web app with the ASP.NET Forms Authentication blog post and let us know how this works for you. Thanks in advance!