I'm trying to add custom 404 pages into umbraco
even though I got them working in several projects, in this umbraco 4.7 it does not work.
so, what do I have,
multi site each with a few languages.
my umbracoSettings contains this:
<errors>
<error404>
<errorPage culture="default">1842</errorPage>
<errorPage culture="en-GB">1842</errorPage>
<errorPage culture="nl-BE">1843</errorPage>
<errorPage culture="fr-BE">1844</errorPage>
</error404>
</errors>
just as it is in other projects
though i keep getting the IIS 404 page.
so, i tried the solution in this topic
both the passThrough and the custom solution don't seem to work
the passThrough gives this:
Page not found No umbraco document matches the url
'http://www.mysite.be/en/facebook'
umbraco tried this to match it using this xpath
query'/domainprefixes-are-used-so-i-do-not-work')
This page can be replaced with a custom 404 page by adding the id of
the umbraco document to show as 404 page in the
/config/umbracoSettings.config file. Just add the id to the
'/settings/content/errors/error404' element.
For more information, visit information about custom 404 on the
umbraco website.
and custom gives this result:
Page not found No umbraco document matches the url
'http://solex.d01-win-dev.be/non-existing-page.aspx?404;http://solex.d01-win-dev.be:80/en/facebook'
umbraco tried this to match it using this xpath
query'/domainprefixes-are-used-so-i-do-not-work')
This page can be replaced with a custom 404 page by adding the id of
the umbraco document to show as 404 page in the
/config/umbracoSettings.config file. Just add the id to the
'/settings/content/errors/error404' element.
For more information, visit information about custom 404 on the umbraco website.
it looks to me as if he does not go towards the umbracoSettings to fetch my error404 mappings.
did something change in 4.7 that you need to activate custom error pages trough a web.config key?
for those people interested, or who might ever have the same issues
it was solved without any of those web.config changes.
but by using a custom 404 handler we added to the 404handlers.config
like this
<notFound assembly="ProjectLibrary" type="Custom404"/>
and still adding the error pages in the umbracoSettings.config
like this
<errors>
<error404>
<errorPage culture="default">1842</errorPage>
<errorPage culture="en-GB">1842</errorPage>
<errorPage culture="nl-BE">1843</errorPage>
<errorPage culture="fr-BE">1844</errorPage>
</error404>
</errors>
the custom handler looks like this:
public class Custom404 : INotFoundHandler
{
#region INotFoundHandler Members
private int _redirectID = -1;
public bool CacheUrl
{
get { return false; }
}
public bool Execute(string url)
{
//Variable for keeping track whether the handling of the request was successful
bool _success = false;
XmlNode error404Node = umbraco.UmbracoSettings.GetKeyAsNode("/settings/content/errors/error404");
// _redirectID =;
XmlNode cultureErrorNode;
try
{
HttpContext.Current.Trace.Write("test", HttpContext.Current.Request.ServerVariables["SERVER_NAME"] + "/" + url);
string sDomein = findDomein(HttpContext.Current.Request.ServerVariables["SERVER_NAME"] + "/" + url);
HttpContext.Current.Trace.Write("test", sDomein);
if (Domain.Exists(sDomein))
{
Domain d = Domain.GetDomain(sDomein);
// test if a 404 page exists with current culture
HttpContext.Current.Trace.Write("test", d.Language.CultureAlias);
cultureErrorNode = error404Node.SelectSingleNode(String.Format("errorPage [#culture = '{0}']", d.Language.CultureAlias));
if (cultureErrorNode != null && cultureErrorNode.FirstChild != null)
{
_redirectID = int.Parse(cultureErrorNode.FirstChild.Value);
}
else
{
cultureErrorNode = error404Node.SelectSingleNode("errorPage [#culture = 'default']");
if (cultureErrorNode != null && cultureErrorNode.FirstChild != null)
_redirectID = int.Parse(cultureErrorNode.FirstChild.Value);
}
}
else
{
cultureErrorNode = error404Node.SelectSingleNode("errorPage [#culture = 'default']");
if (cultureErrorNode != null && cultureErrorNode.FirstChild != null)
_redirectID = int.Parse(cultureErrorNode.FirstChild.Value);
}
}
catch
{
cultureErrorNode = error404Node.SelectSingleNode("errorPage [#culture = 'default']");
if (cultureErrorNode != null && cultureErrorNode.FirstChild != null)
_redirectID = int.Parse(cultureErrorNode.FirstChild.Value);
}
_success = true;
return _success;
}
public string findDomein(string sUrl)
{
if (sUrl.Contains("/"))
{
if (Domain.Exists(sUrl))
{
return sUrl;
}
else
{
sUrl = sUrl.Substring(0, sUrl.LastIndexOf("/"));
return findDomein(sUrl);
}
}
else
{
return sUrl;
}
}
public int redirectID
{
get
{ return _redirectID; }
}
#endregion
}
hope any of you can use it whenever you find yourself in the same situation.
Related
I have created my component to add some desired config fields in Shopware 6. Everything is working fine but one problem that is image is looking as it is being saved in the administration but is not showing any src or else in dump.
And here is my dump preiew having #data null.
can anyone tell what should I do else here?
I will be very thankful.
There is a guide in the docs that explains exactly what your case is.
You can likely extend the \Shopware\Core\Content\Media\Cms\ImageCmsElementResolver and override the getType function:
public function getType(): string
{
return 'my-component-name';
}
The important part of the default ImageCmsElementResolver is the loading the media information. For that you also need in your CMS element resolver. I explain some parts of the existing ImageCmsElementResolver so you can see which steps you need:
public function collect(CmsSlotEntity $slot, ResolverContext $resolverContext): ?CriteriaCollection
{
// read the configuration, that is defined in the Admin JS. Likely also media for you
$mediaConfig = $slot->getFieldConfig()->get('media');
// if this config is NOT containing useful info
if (
$mediaConfig === null
|| $mediaConfig->isMapped()
|| $mediaConfig->isDefault()
|| $mediaConfig->getValue() === null
) {
// return nothing
return null;
}
// otherwise use the configured value as mediaId to load the media entry from the database
$criteria = new Criteria([$mediaConfig->getStringValue()]);
$criteriaCollection = new CriteriaCollection();
$criteriaCollection->add('media_' . $slot->getUniqueIdentifier(), MediaDefinition::class, $criteria);
// return the criterias to execute later, when all needed entities for the CMS page are fetched
return $criteriaCollection;
}
Now the data is fetched and as next step you need to put it into a variable accessible from the Twig template. For this you write into the same CMS element resolver this:
public function enrich(CmsSlotEntity $slot, ResolverContext $resolverContext, ElementDataCollection $result): void
{
$config = $slot->getFieldConfig();
$image = new ImageStruct();
// this is important for accessing data in Twig
$slot->setData($image);
// read the config again
$mediaConfig = $config->get('media');
// if the configuration looks promising
if ($mediaConfig && $config->isStatic() && $mediaConfig->getValue()) {
$image->setMediaId($config->getStringValue());
// look up the media from the entity loading step
$searchResult = $result->get('media_' . $slot->getUniqueIdentifier());
if (!$searchResult) {
return;
}
/** #var MediaEntity|null $media */
$media = $searchResult->get($config->getValue());
// if we do not have a media, then skip it
if (!$media) {
return;
}
// set the media entity to the slot data we just assigned to the slot
$image->setMedia($media);
}
}
After that you should have more info in the slot variable in Twig to embed a media.
I need to remove an object from the PageHandler Header Controls collection in my page template.
I can use the below script to do so at the widget view level, however the one I need to remove has not yet been added at that point, so I need to move it right before it's consumed.
The only accessible place for it that I could find is in my template file - right before #Html.Section("head"). I'm trying to remove the default canonical URL for this template only (some crazy routing stuff going on in this site... don't ask).
var pageHandler = this.ViewContext.HttpContext.Handler.GetPageHandler();
foreach (var c in pageHandler.Header.Controls)
{
if (c != null && c is System.Web.UI.HtmlControls.HtmlLink)
{
System.Web.UI.HtmlControls.HtmlLink mylink = (System.Web.UI.HtmlControls.HtmlLink)c;
if (mylink.Attributes["rel"] == "canonical")
{
pageHandler.Header.Controls.Remove(mylink);
}
}
}
When I try to use this in the template file inside the <head> tag pageHandler.Header is null.
1 - Am I accessing this object in the wrong way for this particular template level? If so, what's the proper object reference?
2 - Is it simply not set yet because of some behind-the-scenes page construction order in Sitefinity? If so, where could/should I handle accessing this object?
3 - Something else is going on entirely?
I AM NOT ASKING HOW TO FIX A NULL REFERENCE EXCEPTION
I understand that the object is null and am trying to find where in the Sitefinity viewmodel at this level this data might be found.
The canonical url is set in Page_PreRenderComplete event which fires after your code in the view has executed.
What I would do is create a new widget, e.g. CanonicalUrlRemover.
In its Index method find the Page object and subscribe to its PreRenderComplete event. Then in the event handler remove the canonical url.
public ActionResult Index()
{
var page = HttpContext.CurrentHandler.GetPageHandler();
page.PreRenderComplete += Page_PreRenderComplete;
return new EmptyResult();
}
private void Page_PreRenderComplete(object sender, System.EventArgs e)
{
var page = sender as System.Web.UI.Page;
if (page != null)
{
var headerControls = page.Header.Controls;
foreach (var c in headerControls)
{
if (c != null && c is System.Web.UI.HtmlControls.HtmlLink)
{
System.Web.UI.HtmlControls.HtmlLink mylink = (System.Web.UI.HtmlControls.HtmlLink)c;
if (mylink.Attributes["rel"] == "canonical")
{
headerControls.Remove(mylink);
}
}
}
}
}
Just drop the widget in this particular page template and you are good to go.
I've got a problem with a LightSwitch 2011 web application using forms authentication.
I've implemented my own login screen which authenticates the user against the active directory. My code also checks to see if the user is assigned to a specific active directory group to decide if they can add / edit / delete data.
The login form is placed on the Login.aspx page. The button to login holds the following code:
protected void buttonLogin_Click(object sender, EventArgs e)
{
LdapAuthentication authentication = new LdapAuthentication();
try
{
bool isUserAdmin = false;
if (authentication.IsUserAuthenticated(textBoxUserName.Text, textBoxPassword.Text, ref isUserAdmin))
{
FormsAuthenticationTicket authenticationTicket = new FormsAuthenticationTicket(1,
textBoxUserName.Text, DateTime.Now, DateTime.Now.AddSeconds(1), false, String.Empty);
//Encrypt the ticket.
string encryptedTicket = FormsAuthentication.Encrypt(authenticationTicket);
//Create a cookie, and then add the encrypted ticket to the cookie as data.
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
//Add the cookie to the outgoing cookies collection.
Response.Cookies.Add(authCookie);
//If the everyoneAdmin is set to true the validation of the administratorgroup
//is decativated so we have to grant the current user administrator rights
if (everyoneAdmin)
isUserAdmin = true;
Session["isUserAdmin"] = isUserAdmin ;
Response.Redirect("default.htm");
}
}
catch (Exception ex)
{
labelError.Text = ex.Message;
labelError.Visible = true;
textBoxPassword.Text = String.Empty;
}
}
public bool IsUserAuthenticated(String userName, String password, ref bool isUserAdmin)
{
if (String.IsNullOrEmpty(userName) || String.IsNullOrEmpty(password))
return false;
String domain = String.Empty;
if (!String.IsNullOrEmpty(ConfigurationManager.AppSettings["Domain"]))
domain = Convert.ToString(ConfigurationManager.AppSettings["Domain"]).Trim();
else
throw new NullReferenceException("The Domain in the configuration must not be null!");
String ldpa = String.Empty;
if (!String.IsNullOrEmpty(ConfigurationManager.AppSettings["LDPA"]))
ldpa = String.Format("LDAP://{0}", Convert.ToString(ConfigurationManager.AppSettings["LDPA"]).Trim());
else
throw new NullReferenceException("The LDPA in the configuration must not be null!");
String administrationGroup = String.Empty;
if (!String.IsNullOrEmpty(ConfigurationManager.AppSettings["AdministratorGroup"]))
administrationGroup = Convert.ToString(ConfigurationManager.AppSettings["AdministratorGroup"]).Trim();
else
throw new NullReferenceException("The AdministrationGroup in the configuration must not be null!");
String domainUserName = String.Format(#"{0}\{1}", domain.Trim(), userName.Trim());
DirectoryEntry directoryEntry = new DirectoryEntry(ldpa, domainUserName, password);
try
{
//Bind to the native AdsObject to force authentication.
object obj = directoryEntry.NativeObject;
DirectorySearcher directorySearcher = new DirectorySearcher(directoryEntry);
directorySearcher.Filter = String.Format("(SAMAccountName={0})", userName.Trim());
directorySearcher.PropertiesToLoad.Add("cn");
directorySearcher.PropertiesToLoad.Add("memberOf");
SearchResult directorySearchResult = directorySearcher.FindOne();
//unable to find a user with the provided data
if (directorySearchResult == null)
return false;
if (directorySearchResult.Properties["memberof"] != null)
{
//If the memberof string contains the specified admin group
for (int i = 0; i < directorySearchResult.Properties["memberof"].Count; i++)
{
string temp = directorySearchResult.Properties["memberof"].ToString();
// get the group name, for example:
if (directorySearchResult.Properties["memberof"].ToString().ToLower().Contains(administrationGroup.ToLower()))
{
isUserAdmin = true;
break;
}
}
}
}
catch (Exception ex)
{
throw new Exception(String.Format("Error authenticating user.\n\rMessage:\n\r {0}", ex.Message));
}
return true;
}
In the class which holds the CanExcecute (server tier) methods I've implemented the following method:
public bool IsCurrentUserAdmin()
{
if (HttpContext.Current.Session["isUserAdmin"] == null)
return false;
return (bool)(HttpContext.Current.Session["isUserAdmin"]);
}
For example, the CanExcecute methods for one table
partial void dtFacilities_CanDelete(ref bool result)
{
result = this.IsCurrentUserAdmin();
}
partial void dtFacilities_CanInsert(ref bool result)
{
result = this.IsCurrentUserAdmin();
}
partial void dtFacilities_CanUpdate(ref bool result)
{
result = this.IsCurrentUserAdmin();
}
WebConfig
<authentication mode="Forms">
<form>s name=".ASPXAUTH"
loginUrl="Login.aspx"
protection="All"
timeout="30"
path="/"
requireSSL="false"
slidingExpiration="true"
defaultUrl="Home.aspx"
cookieless="UseUri" />
</authentication>
<authorization>
<deny users="?">
</deny></authorization>
Problems:
The problem is that if the user is idle for longer than the timeout the session times out. So, the session token isUserAdmin is NULL. At this point I want the application to return to the login screen. A Response.Redirect and a Server.Transfer did not work in the IsCurrentUserAdmin() method. How can I get the application to return the user to the login screen if the session token isUserAdmin is NULL?! Remember, the session token is set in the login.aspx page code behind
When the user closes the final tab of the Lightswitch application, the application opens a new tab and navigates past the login page and they are automatically logged in without processing the login process on the login.aspx page. This means that the session token isUserAdmin is NULL. This happens even if the user has not logged in before they closed the final tab of the application. This leads again to problem 1.
Thanks in advance!
If I understand your problem correctly, if, for whatever reason, isUserAdmin is set to NULL, you want to return the user to to the login screen.
In my application, I simply use a button that the user can click to log off. But the underlying method should work just the same in your case.
First create a new page called LogOff.aspx. The page itself, you can leave default generated code:
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>
For the code behind, you'll want something like this (please check this, I converted from my project which is in VB):
using System.Web.Security;
namespace LightSwitchApplication
{
public partial class LogOff : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
FormsAuthentication.SignOut();
Response.Redirect("default.htm");
}
}
}
This is my code in which I use a button. But if you take the section where the Dispatcher calls Navigate and place it in your IsCurrentUserAdmin() method, it should do the same trick (again, check the C#):
using Microsoft.LightSwitch.Threading;
using System.Windows.Browser;
partial void btnLogOff_Execute()
{
Dispatchers.Main.Invoke(() =>
{
HtmlPage.Window.Navigate(new Uri("LogOff.aspx", UriKind.Relative));
});
}
In my experience, there is a bit of a gotcha in Lightswitch. If you were to execute as is, you would probably receive the following:
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its
dependencies) could have been removed, had its name changed, or is
temporarily unavailable. Please review the following URL and make
sure that it is spelled correctly.
Requested URL: /LogOff.aspx
The fix is this:
First right click your project name in Solution Explorer and Unload Project. Once the project is unloaded, right click it and Edit project_name.lsproj. Ctrl+F for default.htm. You're looking for the section where it is proceeded by _BuildFile. Copy that section from _BuildFile to /_BuildFile, paste below that section and modify as follows.
<_BuildFile Include="Server/LogOff.aspx">
<SubFolder>
</SubFolder>
<PublishType>
</PublishType>
</_BuildFile>
Now right click and Reload your project. If you get errors when trying to build, try Build | Clean and build again. If you run the application in Debug, this code will just reload the page. But once you publish and subsequently cause isUserAdmin to be NULL the code should log you out and take you back to the log on screen.
References:
Original MSDN Forum Thread
My experience implementing it
So I have an xhtml page that contains the following code:
<rich:fileUpload
id="uploadReportTemplate"
addControlLabel="Add XSLT"
fileUploadListener="#{manageFeedTypeAction.fileUploadListener}"
uploadData="#{manageFeedTypeAction.data}"
listWidth="63px" listHeight="0px" maxFilesQuantity="1"
immediateUpload="true" acceptedTypes="xsl,xslt"
allowFlash="false"
status="eventQueueFileUpload"
ontyperejected="javascript:Richfaces.showModalPanel('wrongSelectionModal');this.disabled=false">
<a4j:support event="onuploadcomplete" reRender="fileUploadPanel"/>
</rich:fileUpload>
I am only allowing the user to upload one file. Once this file has been uploaded, I wish to check if the file contains a certain keyword. How can I check whether the file contains that keyword? Please help.
I was able to solve this by adding the following code to the fileUploadListener method being called at fileUploadListener="#{manageFeedTypeAction.fileUploadListener}" above:
public void fileUploadListener(UploadEvent event) {
UploadItem item = event.getUploadItem();
if(item == null || item.getData() == null) {
LOG.error("Uploaded item is null");
} else {
String value = new String(item.getData());
if(value.toLowerCase().contains("String")) {
LOG.error("Cannot contain 'String'");
} else {
setData(item.getData());
setFileName(item.getFileName());
}
}
}
One of the actions of my JPF controller builds up a PDF file and I would like to return this file to the user so that he can download it.
Is it possible to do that or am I forced to write the file somewhere and have my action forward a link to this file? Note that I would like to avoid that as much as possible for security reasons and because I have no way to know when the user has downloaded the file so that I can delete it.
I've tried to access the HttpServletResponse but nothing happens:
getResponse().setContentLength(file.getSize());
getResponse().setContentType(file.getMimeType());
getResponse().setHeader("Content-Disposition", "attachment;filename=\"" + file.getTitle() + "\"");
getResponse().getOutputStream().write(file.getContent());
getResponse().flushBuffer();
We have something similar, except returning images instead of a PDF; should be a similar solution, though, I'm guessing.
On a JSP, we have an IMG tag, where the src is set to:
<c:url value="/path/getImage.do?imageId=${imageID}" />
(I'm not showing everything, because I'm trying to simplify.) In your case, maybe it would be a link, where the href is done in a similar way.
That getImage.do maps to our JPF controller, obviously. Here's the code from the JPF getImage() method, which is the part you're trying to work on:
#Jpf.Action(forwards = {
#Jpf.Forward(name = FWD_SUCCESS, navigateTo = Jpf.NavigateTo.currentPage),
#Jpf.Forward(name = FWD_FAILURE, navigateTo = Jpf.NavigateTo.currentPage) })
public Forward getImage(final FormType pForm) throws Exception {
final HttpServletRequest lRequest = getRequest();
final HttpServletResponse lResponse = getResponse();
final HttpSession lHttpSession = getSession();
final String imageIdParam = lRequest.getParameter("imageId");
final long header = lRequest.getDateHeader("If-Modified-Since");
final long current = System.currentTimeMillis();
if (header > 0 && current - header < MAX_AGE_IN_SECS * 1000) {
lResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
return null;
}
try {
if (imageIdParam == null) {
throw new IllegalArgumentException("imageId is null.");
}
// Call to EJB, which is retrieving the image from
// a separate back-end system
final ImageType image = getImage(lHttpSession, Long
.parseLong(imageIdParam));
if (image == null) {
lResponse.sendError(404, IMAGE_DOES_NOT_EXIST);
return null;
}
lResponse.setContentType(image.getType());
lResponse.addDateHeader("Last-Modified", current);
// public: Allows authenticated responses to be cached.
lResponse.setHeader("Cache-Control", "max-age=" + MAX_AGE_IN_SECS
+ ", public");
lResponse.setHeader("Expires", null);
lResponse.setHeader("Pragma", null);
lResponse.getOutputStream().write(image.getContent());
} catch (final IllegalArgumentException e) {
LogHelper.error(this.getClass(), "Illegal argument.", e);
lResponse.sendError(404, IMAGE_DOES_NOT_EXIST);
} catch (final Exception e) {
LogHelper.error(this.getClass(), "General exception.", e);
lResponse.sendError(500);
}
return null;
}
I've actually removed very little from this method, because there's very little in there that I need to hide from prying eyes--the code is pretty generic, concerned with images, not with business logic. (I changed some of the data type names, but no big deal.)