500 Custom Error Pages - sitecore

I want to implement 500 error page for multi-sites/multi-languages, i am following this article.
But Application_Error in Global.asax is not firing. Here is my code:
<%# Application Language='C#' Inherits="Sitecore.ContentSearch.SolrProvider.CastleWindsorIntegration.WindsorApplication" %>
<script RunAt="server">
private void Application_Error(object sender, EventArgs e)
{
var customErrorsSection = (System.Web.Configuration.CustomErrorsSection)ConfigurationManager.GetSection("system.web/customErrors");
var lastException = Server.GetLastError();
if (customErrorsSection.Mode != System.Web.Configuration.CustomErrorsMode.Off)
{
try
{
// Log.Error( "There was an error in the application", lastException);
Server.ClearError();
HttpContext.Current.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
Server.Transfer(string.Format("/Error/{0}_500.html", GetSafeLanguage()));
}
catch
{
}
}
}
private string GetSafeLanguage()
{
try
{
return Sitecore.Context.Language.CultureInfo.TwoLetterISOLanguageName;
}
catch
{
}
return string.Empty;
}
</script>

Since I am using SOLR, It needs WindsorApplication in Global.asax and this class not inherited from System.Web.HttpApplication, i follow these links to handle 500 page error :
https://sitecorecommerce.wordpress.com/2015/10/15/500-error-page-in-your-sitecore-application/
http://www.partechit.nl/en/blog/2014/01/sitecore-mvc-applications-and-the-application-error-event
Connfiguation :
<pipelines>
<mvc.exception>
<processor type="Sitecore.Mvc.Pipelines.MvcEvents.Exception.ShowAspNetErrorMessage, Sitecore.Mvc">
<patch:attribute name="type">MyWebsite.Web.Pipelines.HandleMvcException, MyWebsite.Web</patch:attribute>
</processor>
</mvc.exception>
</pipelines>
My Class
public class HandleMvcException : ExceptionProcessor
{
public override void Process(ExceptionArgs args)
{
var customErrorsSection = (CustomErrorsSection)ConfigurationManager.GetSection("system.web/customErrors");
var context = args.ExceptionContext;
var httpContext = context.HttpContext;
var exception = context.Exception;
if (customErrorsSection.Mode != CustomErrorsMode.Off)
{
if (context.ExceptionHandled || httpContext == null || exception == null)
{
return;
}
// Create a report with exception details.
string exceptionInfo = this.GetExceptionInfo(httpContext, exception);
// Store the report in a session variable so we can access it from the custom error page.
Log.Error(string.Format("There was an error in {0} : {1}", Sitecore.Context.Site.Name, exceptionInfo),this);
// Return a 500 status code and execute the custom error page.
httpContext.Server.ClearError();
httpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
httpContext.Server.Execute((Sitecore.Context.Site.ErrorPage(GetSafeLanguage())));
}
}
private string GetExceptionInfo(HttpContextBase httpContext, Exception exception)
{
// Generate an error report.
var errorInfo = new StringBuilder();
errorInfo.AppendLine(string.Concat("URL: ", httpContext.Request.Url));
/* Snipped additional lines of report generation */
errorInfo.AppendLine(string.Concat("Source: ", exception.Source));
errorInfo.AppendLine(string.Concat("Message: ", exception.Message));
errorInfo.AppendLine(string.Concat("Stacktrace: ", exception.StackTrace));
return errorInfo.ToString();
}
private string GetSafeLanguage()
{
try
{
return Sitecore.Context.Language.CultureInfo.TwoLetterISOLanguageName;
}
catch
{
}
return string.Empty;
}
}
and in site definition i added custom attribute for error page :
<site name="mywebsite" patch:before="site[#name='website']" xdt:Transform="Replace" xdt:Locator="Match(name)"
hostName ="mywebsite.local"
virtualFolder="/"
physicalFolder="/"
rootPath="/sitecore/content/mywebsite"
startItem="/home"
database="web"
domain="extranet"
allowDebug="true"
cacheHtml="true"
htmlCacheSize="50MB"
enablePreview="true"
enableWebEdit="true"
enableDebugger="true"
disableClientData="false"
errorPage="/assets/error/mywebsite/{0}_500.html"/>
and I created extended method to read the errorPage attribute :
public static class SiteExtension
{
/// <summary>
/// Retrun the site unique ID
/// </summary>
/// <returns></returns>
public static string ErrorPage(this SiteContext site, string language)
{
try
{
string errorPage = site.Properties["errorPage"];
if (!String.IsNullOrEmpty(errorPage))
return string.Format(errorPage, language);
else
return string.Empty;
}
catch (Exception)
{
return string.Empty;
}
}
}

Related

consuming asmx webservice in xamarin forms

I am working on a login page in Xamarin forms and I need to consume an asmx webservice in order to connect to the sql server. I used this example: https://github.com/fabiosilvalima/FSL.ConsummingAsmxServicesInXamarinForms, and tried to apply the same steps for my app. but I got an error.
here's my code:
ILogin.cs:
namespace App33.Models
{
public interface ILogin
{
string Error { get; set; }
bool ValidUser { get; set; }
}
}
ILoginSoapService.cs
public interface ILoginSoapService
{
Task<List<ILogin>> Login(string namee, string passs);
}
in App.xaml.cs
private static ILoginSoapService _loginSoapService;
public static ILoginSoapService LoginSoapService
{
get
{
if (_loginSoapService == null)
{
_loginSoapService = DependencyService.Get<ILoginSoapService>();
}
return _loginSoapService;
}
Main.xaml.cs
public MainPage()
{
InitializeComponent();
}
async void OnButtonClicked(object sender, EventArgs e)
{
var entr_usrname = this.FindByName<Entry>("username");
string usrname = entr_usrname.Text;
var entr_pass = this.FindByName<Entry>("Password");
string pass = entr_pass.Text;
var state = await App.LoginSoapService.Login(usrname,pass);
if (state[0].ValidUser == true)
{
await DisplayAlert("Alert", "You have been alerted", "OK");
}
}
this is for the portable app. my webservice is added to the web reference as LoginWs. it has the following codes:
Result.cs:
public class Result
{
public string Error { get; set; }
public bool ValidUser { get; set; }
}
WebService1.asmx.cs:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class WebService1 : System.Web.Services.WebService
{
[WebMethod]
public Result Login(string userName, string userPass)
{
SqlConnection conn=new SqlConnection (new DBConnection().ConnectionString);
Result result = new Result();
try
{
SqlCommand cmd = new SqlCommand("SELECT userName, password FROM users where CONVERT(VARCHAR, username)=#username and CONVERT(VARCHAR, password)=#password");
cmd.Parameters.AddWithValue("username", userName);
cmd.Parameters.AddWithValue("password", userPass);
cmd.Connection = conn;
if (conn.State==System.Data.ConnectionState.Closed)
{
conn.Open();
}
SqlDataReader dr = cmd.ExecuteReader();
if (dr.HasRows)
{
result.ValidUser = true;
return result;
}
else
{
result.ValidUser = false;
}
}
catch(Exception ex)
{
result.Error = ex.ToString();
}
finally
{
conn.Close();
}
return result;
}
}
}
now in App.Android:
Result.cs
namespace App33.Droid.LoginWs
{
public partial class Result : ILogin
{
}
}
LoginSoapService.cs
[assembly: Dependency(typeof(App33.Droid.LoginSoapService))]
namespace App33.Droid
{
public sealed class LoginSoapService :ILoginSoapService
{
LoginWs.WebService1 service;
public LoginSoapService()
{
service = new LoginWs.WebService1()
{
// Url = "http://codefinal.com/FSL.ConsummingAsmxServicesInXamarinForms/Customers.asmx" //remote server
Url = "http://192.168.0.106/site2/WebService1.asmx" //localserver - mobile does not understand "localhost", just that ip address
};
}
public async Task<List<ILogin>> Login( string namee,string pass)
{
return await Task.Run(() =>
{
var result = service.Login(namee,pass);
return new List<ILogin>(result);
});
}
}
}
the error i'm getting is in this line:return new List(result);. it says: Error CS1503 Argument 1: cannot convert from 'App33.Droid.LoginWs.Result' to 'int'. I can't figure out what the peoblem is. sorry for the long question. any help is appreciated.

Custom Provider for AWS SSM using Microsoft.Configuration.ConfigurationBuilders

I seem to be stuck at developing a custom Key/Value pair provider for Amazon's System Manager Parameter Store (SSM) using NETFramework 4.7.1 that utilizes Microsoft.Configuration.ConfigurationBuilders.
The implementation:
using System;
using System.Collections.Generic;
using Amazon.SimpleSystemsManagement;
using Amazon.SimpleSystemsManagement.Model;
using Microsoft.Configuration.ConfigurationBuilders;
using System.Linq;
using System.Diagnostics;
using System.Collections.Specialized;
using Amazon.Runtime;
using Amazon.Runtime.CredentialManagement;
using System.Configuration;
using System.Threading.Tasks;
namespace AXS.Configurations
{
public class ParameterStoreConfigBuilder : KeyValueConfigBuilder
{
public const string envTag = "Environment";
public const string appNameTag = "AppName";
private IAmazonSimpleSystemsManagement client;
/// <summary>
/// Gets or sets an environment (dev|qa|staging|production)
/// </summary>
public string Environment { get; set; }
/// <summary>
/// Gets or sets a AppName
/// </summary>
public string AppName { get; set; }
public ParameterStoreConfigBuilder(IAmazonSimpleSystemsManagement client,
string appName,
string environment)
{
this.client = client;
Environment = environment.ToLower();
AppName = appName;
}
public ParameterStoreConfigBuilder()
{
client = new AmazonSimpleSystemsManagementClient();
}
public override string Description => "Parameter Store";
public override string Name => "SSM";
protected override void LazyInitialize(string name, NameValueCollection config)
{
Optional = false;
base.LazyInitialize(name, config);
string env = UpdateConfigSettingWithAppSettings(envTag);
if (string.IsNullOrWhiteSpace(env))
throw new ArgumentException($"environment must be specified with the '{envTag}' attribute.");
Environment = env;
string appName = UpdateConfigSettingWithAppSettings(appNameTag);
if (string.IsNullOrWhiteSpace(appName))
throw new ArgumentException($"appName must be specified with the '{appNameTag}' attribute.");
AppName = appName;
client = new AmazonSimpleSystemsManagementClient("","", Amazon.RegionEndpoint.USWest2);
}
public override ICollection<KeyValuePair<string, string>> GetAllValues(string prefix)
{
Trace.TraceInformation($"return values prefix {prefix}");
if (client == null)
return null;
var parameters = new List<Parameter>();
string nextToken = null;
do
{
var response = client.GetParametersByPath(new GetParametersByPathRequest { Path = prefix, Recursive = true, WithDecryption = true, NextToken = nextToken });
nextToken = response.NextToken;
parameters.AddRange(response.Parameters);
} while (!string.IsNullOrEmpty(nextToken));
return parameters.Select(p => new
{
Key = p.Name,
p.Value
}).ToDictionary(parameter => parameter.Key, parameter => parameter.Value, StringComparer.OrdinalIgnoreCase);
}
public override string GetValue(string key)
{
return Task.Run(async () => { return await GetValueAsync(key); }).Result;
}
private async Task<string> GetValueAsync(string key)
{
var name = $"/{Environment}/{AppName}/{key.Replace(':', '/')}";
Trace.WriteLine($"get value async:{name}");
if (client == null)
return null;
try
{
Trace.TraceInformation($"fetch key {name}");
var request = new GetParameterRequest
{
Name = name,
WithDecryption = true
};
var response = await client.GetParameterAsync(request);
var parameter = response.Parameter;
var value = parameter.Type == ParameterType.SecureString ? "*****" : parameter.Value;
Trace.TraceInformation($"fetched name={name} value={value}");
return value;
}
catch (Exception e) when (Optional && ((e.InnerException is System.Net.Http.HttpRequestException) || (e.InnerException is UnauthorizedAccessException))) { }
return null;
}
}
}
The problem seems to be that AWS SSM client never gets created.
If I change the code and try to instantiate in the constructor I get a stack overflow exception due to recursion.
Any ideas on how to force to get AmazonSimpleSystemsManagementClient created?
The code uses guidance from https://github.com/aspnet/MicrosoftConfigurationBuilders
The App.Config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="configBuilders" type="System.Configuration.ConfigurationBuildersSection,
System.Configuration, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a"
restartOnExternalChanges="false"
requirePermission="true" />
</configSections>
<configBuilders>
<builders>
<add name="ParameterStore" Environment="development" AppName="myAppNameforParmStore" type="AXS.Configurations.ParameterStoreConfigBuilder, AXS.Configurations" />
<add name="Env" prefix="appsettings_" stripPrefix="true" type="Microsoft.Configuration.ConfigurationBuilders.EnvironmentConfigBuilder, Microsoft.Configuration.ConfigurationBuilders.Environment, Version=2.0.0.0, Culture=neutral" />
</builders>
</configBuilders>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.1" />
</startup>
<appSettings configBuilders="Env,ParameterStore">
<add key="Url" value="URL Value for from paramter Store" />
<add key="Secret" value="Some Secret value decrypted" />
</appSettings>
</configuration>
Thanks
UPDATE
I posted an updated version of the AwsSsmConfigurationBuilder, and a sample ASP.NET Web Forms project that uses it, on my GitHub:
https://github.com/Kirkaiya/AwsSsmConfigBuilderPoC/
Disclaimer: This is a proof-of-concept (POC) for a custom ConfigurationBuilder for ASP.NET 4.7.1 or higher (running on .NET Framework obviously). It's a POC, so it doesn't do anything besides allow you store Configuration AppSettings in AWS Parameter Store (a feature of Simple Systems Manager). So, clearly, don't use this in production without productizing and testing it!
Prerequisites:
Your project must target .NET Framework 4.7.1 or higher
Include NuGet package Microsoft.Configuration.ConfigurationBuilders.Base
Have parameters in AWS SSM Parameter Store that have the same name (not counting the prefix) as parameters in your web.config file, and vice-versa.
Notes
In order to avoid recursively calling a concrete constructor or Initialize, I used a static constructor to instantiate the AmazonSimpleSystemsManagementClient, which is held in a static member.
Web.Config additions
Note: change the assembly/class-name of your builder to match yours, etc.
<configSections>
<section name="configBuilders" type="System.Configuration.ConfigurationBuildersSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" restartOnExternalChanges="false" requirePermission="false" />
</configSections>
<configBuilders>
<builders>
<add name="ParameterStore" ssmPrefix="/padnugapp/ApiKeys" type="Microsoft.Configuration.ConfigurationBuilders.AwsSsmConfigBuilder, AspNetWebFormsSample" />
</builders>
</configBuilders>
<appSettings configBuilders="ParameterStore">
<add key="TestKey" value="TestKey Value from web.config" />
<add key="TwitterKey" value="TwitterKey value from web.config" />
</appSettings>
And the AwsSsmConfigBuilder.cs file:
namespace Microsoft.Configuration.ConfigurationBuilders
{
public class AwsSsmConfigBuilder : KeyValueConfigBuilder
{
private string BaseParameterPath = "/padnugapp/ApiKeys";
private static IAmazonSimpleSystemsManagement _client;
static AwsSsmConfigBuilder()
{
_client = new AmazonSimpleSystemsManagementClient();
}
public override void Initialize(string name, NameValueCollection config)
{
base.Initialize(name, config);
if (config["ssmPrefix"] == null)
return;
BaseParameterPath = config["ssmPrefix"];
}
public override ICollection<KeyValuePair<string, string>> GetAllValues(string prefix)
{
if (_client == null)
return null;
var request = new GetParametersByPathRequest
{
Path = $"{BaseParameterPath}/{prefix}",
WithDecryption = true,
};
var response = _client.GetParametersByPathAsync(request).Result;
var result = response.Parameters.ToDictionary(param => param.Name, param => param.Value, StringComparer.OrdinalIgnoreCase);
return result;
}
public override string GetValue(string key)
{
if (_client == null)
return null;
var request = new GetParameterRequest
{
Name = $"{BaseParameterPath}/{key}",
WithDecryption = true,
};
var response = _client.GetParameterAsync(request).Result;
return response.Parameter.Value;
}
}
}
The code I put into a web-forms (.aspx) page that renders the two appSettings items in HTML:
TestKey =
<%=(System.Configuration.ConfigurationManager.AppSettings["TestKey"]) %>
<br />
TwitterKey =
<%=(System.Configuration.ConfigurationManager.AppSettings["TwitterKey"]) %>
I can't stress enough that this is just for a demo I'm doing, and not tested in any way, shape or form except on my laptop ;-)

How to forward service?wsdl to service.wsdl in Spring WS

At the first sorry for my awful English. I have following piece of Spring WS configuration:
#Configuration
class WSConfig {
...
#Bean
Wsdl11Definition wsdlSchema() {
SimpleWsdl11Definition wsdl11Definition = new SimpleWsdl11Definition();
wsdl11Definition.setWsdl(new ClassPathResource("service.wsdl"));
return wsdl11Definition;
}
}
So I can get WSDL file using URL */service.wsdl.
Is it possible to add URL forwarding */service?wsdl --> */service.wsdl cause of some WS clients use URL */service?wsdl.
Possible solution is extending MessageDispatcherServlet
class CustomMessageDispatcherServlet extends MessageDispatcherServlet {
private static final String WSDL_SUFFIX_NAME = ".wsdl";
private Map<String, WsdlDefinition> wsdlDefinitions;
CustomMessageDispatcherServlet(ApplicationContext applicationContext) {
super();
setApplicationContext(applicationContext);
setTransformWsdlLocations(true);
setTransformSchemaLocations(false);
}
#Override
protected void initStrategies(ApplicationContext context) {
super.initStrategies(context);
initWsdlDefinitions(context);
}
private void initWsdlDefinitions(ApplicationContext context) {
wsdlDefinitions = BeanFactoryUtils
.beansOfTypeIncludingAncestors(
context, WsdlDefinition.class, true, false);
}
// here with dealing with "wsdl" parameter in HTTP GET request
#Override
protected WsdlDefinition getWsdlDefinition(HttpServletRequest request) {
if (HttpTransportConstants.METHOD_GET.equals(request.getMethod()) &&
(request.getRequestURI().endsWith(WSDL_SUFFIX_NAME) || request.getParameter("wsdl") != null)) {
String fileName = WebUtils.extractFilenameFromUrlPath(request.getRequestURI());
return wsdlDefinitions.get(fileName);
} else {
return null;
}
}
}

Sitecore Publishing Restriction Override

I have two publishing target - one is stage and one is production.The publishing on Production should adhere to the publishing restrictions, but publishing on Stage should not look at or discard the valid to and valid from dates and publish under any circumstance.
I have written a publishing pipeline (PipelinePublishProvider). I am not sure how could I manage to overwrite the field values temporarily so it publishes on to stage every-time.
public class StagePublishOverride : PipelinePublishProvider
{
public override PublishHelper CreatePublishHelper(PublishOptions options)
{
Assert.ArgumentNotNull(options, "options");
if (options.TargetDatabase.Name.ToLower() == "stage")
{
Item itemToBePublished = new Item(options.RootItem.ID, options.RootItem.InnerData, new Database("web"));
itemToBePublished.Editing.BeginEdit();
itemToBePublished.Publishing.ValidTo = DateTime.MaxValue;
itemToBePublished.Publishing.ValidFrom = DateTime.MinValue;
itemToBePublished.Editing.EndEdit();
options.RootItem = itemToBePublished;
}
if (options is ExtendedPublishOptions)
return new ExtendedPublishHelper(options as ExtendedPublishOptions);
return new PublishHelper(options);
}
}
public class ExtendedPublishHelper : PublishHelper
{
private readonly ExtendedPublishOptions _options;
public ExtendedPublishHelper(ExtendedPublishOptions options)
: base(options)
{
_options = options;
}
public override Item GetVersionToPublish(Item sourceItem)
{
Assert.ArgumentNotNull(sourceItem, "sourceItem");
if (Options is ExtendedPublishOptions)
{
return sourceItem.Publishing.GetValidVersion(Options.PublishDate, _options.RequireApproval);
}
return sourceItem.Publishing.GetValidVersion(Options.PublishDate, true);
}
}
public class ExtendedPublishOptions : PublishOptions
{
public ExtendedPublishOptions(Database sourceDatabase, Database targetDatabase, PublishMode mode, Language language, DateTime publishDate, bool requireApproval)
: base(sourceDatabase, targetDatabase, mode, language, publishDate)
{
RequireApproval = requireApproval;
}
public bool RequireApproval { get; set; }
}
}
I believe you'll be better off adding a processor to the publishItem pipeline. Here is some UNTESTED code, which I think will serve your purpose:
public class PublishOverride : PublishItemProcessor
{
public override void Process(PublishItemContext context)
{
Assert.ArgumentNotNull((object)context, "context");
if (context.Action != PublishAction.None)
return;
Item sourceItem = this.GetSourceItem(context);
if (sourceItem == null)
return;
var stagingDB = Factory.GetDatabase("Stage");
if (stagingDB != null && !sourceItem.Publishing.NeverPublish && context.PublishContext.PublishOptions.TargetDatabase == stagingDB)
{
context.Action = PublishAction.PublishVersion;
context.VersionToPublish = sourceItem;
}
}
private Item GetSourceItem(PublishItemContext context)
{
Assert.ArgumentNotNull((object)context, "context");
return context.PublishHelper.GetSourceItem(context.ItemId);
}
}
Make sure you patch it in before the DetermineAction processor in the default config. So your config patch would look like this:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:x="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<publishItem>
<processor patch:before="*[#type='Sitecore.Publishing.Pipelines.PublishItem.DetermineAction, Sitecore.Kernel']"
type="YourNamespace.PublishOverride, YourAssembly" />
</publishItem>
</pipelines>
</sitecore>
</configuration>

Unit testing ExceptionFilterAttribute

I'm trying to unit test my exception filter code. I can validate the exception, but I can't seem to find the exception message to validate in the unit test. Here is my code...
public class ExceptionHandlingAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is TimeoutException)
{
context.Response = context.Request.CreateErrorResponse(HttpStatusCode.RequestTimeout, context.Exception.Message);
return;
}
if (context.Exception is UnauthorizedAccessException)
{
context.Response = context.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, context.Exception.Message);
return;
}
context.Response = context.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Unable to process your request.");
}
}
Unit Test Code
[Theory, MemberData("ExceptionData")]
public void OnExceptionTests(Exception ex, HttpStatusCode statusCode)
{
var request = new HttpRequestMessage();
var actionContext = InitializeActionContext(request);
var httpActionExectuedContext = new HttpActionExecutedContext(actionContext, ex);
var exceptionHandlingAttribute = new ExceptionHandlingAttribute();
exceptionHandlingAttribute.OnException(httpActionExectuedContext);
Assert.Equal(actionContext.Response.StatusCode, statusCode);
Assert.Equal(actionContext.Response.ReasonPhrase, ex.Message);
}
public static IEnumerable<object[]> ExceptionData
{
get
{
return new[]
{
new object[] { new TimeoutException("My timeout message."), HttpStatusCode.RequestTimeout }
};
}
}
My problem is : Assert.Equal(actionContext.Response.ReasonPhrase, ex.Message);
When I try to look at it in the watch window, I can't seem to find "My Timeout message" in the response.
UPDATE:
actionContext.Response.ReasonPhrase = "Request Timeout"
ex.Message = "My timeout message"
The message portion of the CreateErrorResponse isn't a property, you have to read the content to get the value. Here's what I did...
var responseContent = await actionContext.Response.Content.ReadAsStringAsync();
After reading, responseContent now had:
{ "message" : "My timeout message." }