I am using WFFM Custom Save action methods. Here I am executing some service and getting response , I have to display response in next page.I used below code but its not working.
internal class WffmCustomSaveAction : WffmSaveAction
{
public override void Execute(ID formId, AdaptedResultList adaptedFields, ActionCallContext actionCallContext, params object[] data)
{
HttpContext.Current.Response.Clear();
StringBuilder sb = new StringBuilder();
sb.Append("<html>");
sb.AppendFormat(#"<body onload='document.forms[""form""].submit()'>");
sb.AppendFormat("<form name='form' action='{0}' method='post'>", "http://local.website/thankyoupage");
sb.AppendFormat("<input type='hidden' name='id' value='{0}'>", "id123");
// Other params go here
sb.Append("</form>");
sb.Append("</body>");
sb.Append("</html>");
HttpContext.Current.Server.Transfer(sb.ToString());
HttpContext.Current.Response.End();
}
}
You should not use a SaveAction to do the redirect to your thankyou page. You can use the Sitecore pipelines to change the redirect url. A working example can be found here for MVC forms (Webforms pipelines are mentioned as well, but without code example).
All comes down to finding the correct pipelines in
Sitecore. In this case you need a pipeline in case of success. But be aware: there is a big difference between the webforms and mvc solution.
Webforms: The pipeline in case of webforms are: <successAction>
This can be found in Sitecore.Forms.config.
Mvc: The pipeline in case of mvc are: <wffm.success>
This can be found in Sitecore.MvcForms.config.
Related
Is there any way to send mails to certain users based on a condition in ECM 2.1 . For example, I want to send mails to only those users whose user profile property Country='USA'. Is there a way to do this in ECM 2.1?
Earlier for ECM 1.3 we used to use a third party segmentation module below
https://marketplace.sitecore.net/en/Modules/Sitecore_EmailCampaign_Segment.aspx
But it does not support ECM 2.1. So I was wondering how to implement it in ECM 2.1 . By the way we are using Sitecore 7.2
If you don't mind extending ECM slightly you could tap into the DispatchNewsletter Pipline.
If you add processor like the following, you could get all the users dynamically and add them to the subscribers list. You just need to make sure that this only fires on certain scenarios to avoid this interfering with the core product functionality.
public class GetUSASubscribers
{
public void Process(DispatchNewsletterArgs args)
{
if(CanProcessEmail(args))
{
var matches = UserManager.GetUsers().Where(usr => usr.Profile["Country"].Equals("USA")).ToList();
foreach (var username in matches)
{
if (User.Exists(username.Name))
{
var contact = Contact.FromName(username.LocalName);
args.Message.Subscribers.Add(contact);
args.Message.SubscribersNames.Add(contact.Name);
}
}
}
}
}
You can register the processor as follows in your Sitecore.EmailCampaign.config
<DispatchNewsletter>
<processor type="Sitecore.Modules.EmailCampaign.Core.Pipelines.DispatchNewsletter.CheckPreconditions, Sitecore.EmailCampaign" />
<processor type="YourClass, YourNamespace" />
........................
</DispatchNewsletter>
To make it more dynamic you could add a Rules engine field to each message item to determine which users are added to the subscriber list. So the logic e.g where user profile["country"] equals 'USA' could be in the rules field.
For reference, some more detail on the set up of rules in Sitecore.
http://blog.horizontalintegration.com/2013/12/06/bending-the-sitecore-rules-field-to-your-will-with-sitecore-7-1-part-1/
I have a Web Form for Marketer set up done for one of my Pages.
I have Custom Submit Action written for it as shown below in the code snippet -
public class **CustomFormSubmit : ISaveAction**
{
public void Execute(ID formid, AdaptedResultList fields, params object[] data)
{
try
{
**//var returnValue= Custom Logic to save form data // returns true or false**
}
catch (Exception ex)
{
Logger.Log(ex.Message + ":" + builder, ExceptionCategory.Error);
throw;
}
}
In my above Web form - Success Mode is - SuccessMode/Redirect and I have a success Page configured for it.
My requirement in above scenario is to keep user on the same Page(with Form) if returnValue is false . (as shown in above code snippet)
Can anyone Please guide me in the above scenario as - how to keep user on the same Page with values filled in the form so that user can submit it again.
Product Details - 7.2 rev. 141226 , Web Forms for Marketers 2.4 rev.140117
To add further details -
I am not sure how can I go back to my page instead of the redirection in case if return is false in the above code snippet.
As soon the submit button is clicked the above function- Execute- gets called.
How do I go back to the Page - Do I need to override any function or customize something.
If any exception comes while saving data- then the control goes back to the same Page with all values filled by user retained -with the Save Action Failed Message which is configured in Sitecore .
So my requirement will be to go to to the form as happening in case of Exception when false comes as return value while saving data and to put customised Error Messages which might change each time, so not statically configured ,rather a dynamic one.
Thanks!
Saurabh
One option will be to redirect to the original page with the Form on.
Enable your form to populate the fields via Query String using the ReadQueryString property, via Presentation Details of the Form Renderer:
So on false of your Save Action you create a collection of query strings with the name of each Field, as it appears in the Form, followed by the User's value.
The code below will loop through all your fields and arrange them into a QueryString with its FieldName and Value;
string urlOfForm = HttpContext.Current.Request.Url.AbsolutePath;
var queryString = new StringBuilder("?");
foreach (AdaptedControlResult field in fields)
{
queryString.Append(string.Format("{0}={1}&", field.FieldName, field.Value));
}
urlOfForm = urlOfForm + queryString;
HttpContext.Current.Response.Redirect(urlOfForm);
Sitecore will then automatically populate the appropriate fields with the values, achieving your requirement.
EDIT
I have found that most Exceptions thrown will take the user back to the Form with their values populated. You can then pass in the cause of the failure to write to your CRM. See below for Example
if (submitFailed)
{
throw new Exception("The email address entered already exists in our System");
}
The complexity then comes in dynamically swapping out the Save Action Failed Message to show this Exception Message. All posts I find about custom Save Action Message state the only real approach is to redirect via your Custom Save Action to a different page showing a different message. Which is not suitable to your requirements.
I have found the pipeline Args you are going to need to patch FormSubmitFailedArgs and SubmitFailedArgs. The Former will need the following change
public FormSubmitFailedArgs(ID formID, AdaptedResultList fields, ID actionFailed, Exception ex)
: base(formID, actionFailed, ex)
{
this.Fields = fields;
this.ErrorMessage = ex.Message;
}
and the Latter will need
public SubmitFailedArgs(ID formID, ID actionFailed, string errorMessage, Exception innerException)
{
this.FormID = formID;
this.ActionFailed = actionFailed;
this.ErrorMessage = innerException.Message;
this.InnerException = innerException;
}
Location and Styling of Submit Message:
You need to find the FormRender sublayout file, this is defaulted to website\sitecore modules\Web\Web Forms for Marketers\Control\SitecoreSimpleFormAscx.ascx inside there you will find a compont called SubmitSummary this renders out the submit message so move it to where you require.
Also note it references the CssClass scfSubmitSummary this is what you will need to target to change the styling of the Message. This Answer is already REALLY long so I won't give a blow by blow how to change the styling of that class, see here for example - http://www.awareweb.com/awareblog/10-1-13-wffmguide
Pipeline Patching
I've dug in deeper, in order to use the custom Args we created for using the exception error message you will need to control the Pipeline which ultimately uses those Args, this is the processor Sitecore.Form.Core.Pipelines.FormSubmit.FormatMessage, Sitecore.Forms.Core in the <errorSubmit> Pipeline.
From my investigation it shouldn't take much effort then its a matter of patching it, you can modify if the Sitecore.Forms.config directly or use patch:instead from a config file within the App_Config/Includes folder - see here for more info.
One option would be to create a Custom Form Verification Action. You could save the data here, although it would be better to verify the data against your API here and then save the data in custom save action, simply since this seems more logical as to how WFFM was meant to function.
using Sitecore.Data;
using Sitecore.Form.Core.Controls.Data;
using Sitecore.Form.Core.Submit;
using System;
using System.Collections.Generic;
namespace Custom.WFFM
{
public class CustomVerificationStep : BaseCheckAction
{
public string FailedMessage { get; set; }
public override void Execute(ID formid, IEnumerable<ControlResult> fields)
{
// Call your API
// You have access to the fields, so you can pass them through as parameters to your if needed
bool flag = ServiceAPI.ValidateUserData(param1, param2, etc);
if (!flag)
{
throw new Exception(string.Format(this.FailedMessage ?? "There was an error while verifying the data against the service call"));
}
}
public override ActionState QueryState(ActionContext context)
{
return ActionState.DisabledSingleCall;
}
}
}
Create the corresponding Verification Action under /sitecore/system/Modules/Web Forms for Marketers/Settings/Actions/Form Verification:
You can change the error message by setting it in the Parameters field as <FailedMessage>Custom Failed Error Message</FailedMessage>.
And then add your verification step to your form:
If you need a different error message per form then you can set the error message to display from the Error Messages tab.
The user will then be returned to the same without any of the save actions being called and the form fields still filled in.
We are using ASP.NET MVC 5.0 to build a website. If I enter into a textbox some javascript when I save I get a "potentially unsafe input detected" error page - great.
However a couple of our screens use a ajax submit to pass json directly to the controller this seems to skip the validation above.
Is there any way to call the standard validation on the model (or each text field in the model) in the controller in order to throw the error above.
i.e. something like
public override ActionResult Create(MyModel myModel)
{
/* Any dubious input this should throw an error*/
AntiXSS.ValidateInput(myModel);
...
I ran into a similar issue, and as noted in comments on other answer, we had JQuery using $.ajax to post JSON to the MVC action. The default model binder does not validate posted JSON allowing unsafe XSS to be posted against our action.
To solve this, I found the RequestValidator has a static method InvokeIsValidRequestString that allowed
public class ValidateJsonXssAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var request = filterContext.HttpContext?.Request;
if (request != null && "application/json".Equals(request.ContentType, StringComparison.OrdinalIgnoreCase))
{
if (request.ContentLength > 0 && request.Form.Count == 0) //
{
if (request.InputStream.Position > 0)
request.InputStream.Position = 0; // InputStream has already been read once from "ProcessRequest"
using (var reader = new StreamReader(request.InputStream))
{
var postedContent = reader.ReadToEnd(); // Get posted JSON content
var isValid = RequestValidator.Current.InvokeIsValidRequestString(HttpContext.Current, postedContent,
RequestValidationSource.Form, "postedJson", out var failureIndex); // Invoke XSS validation
if (!isValid) // Not valid, so throw request validation exception
throw new HttpRequestValidationException("Potentially unsafe input detected");
}
}
}
}
}
Then, you can just decorate relevant MVC actions expecting JSON-posted data that might bypass the standard XSS prevention:
[HttpPost]
[ValidateJsonXss]
public ActionResult PublishRecord(RecordViewModel vm) { ... }
You can see other options for customizing request validation with OWASP .NET recommendations by extending the RequestValidator object, which exposes the string validation done by the ValidateInput automatically utilized by MVC for other scenarios of query string, form collection, and cookie values.
For more info: https://www.owasp.org/index.php/ASP.NET_Request_Validation
[ValidateInput] attribute can be attached to each method. http://www.c-sharpcorner.com/UploadFile/dacca2/validateinput-attribute-to-prevent-css-attack-in-mvc/
I know that it is possible to enroll users in an engagement plan from with Sitecore by adding them to a specific state in the plan when they visit a campaign URL, adding them when they submit a Web Forms for Marketers Form, and manually adding them in the Supervisor interface.
Additionally, I know that you can use the API to add a user as described here:
http://briancaos.wordpress.com/2013/06/03/programming-for-sitecore-dms-engagement-plans/
However, that method requires a username.
I would like to enroll anonymous users in an engagement plan when they visit any page represented by a particular template in Sitecore (ie, page from the Product template). Is this possible using the API?
To expand on my above comment, and to supplement your own answer, here's a processor that you could add to the after the ItemResolver in the httpRequestBegin pipeline that would achieve the desired result. It is a very basic version that you could embellish as you see fit
class CampaignRedirect
{
public void Process(HttpRequestArgs args)
{
var request = HttpContext.Current.Request;
// must not already have the querystring in the URL
if(request.QueryString["sc_camp"] != null &&
request.QueryString["sc_camp"] != "XXXXXXXX")
return;
// must have a context item
if(Sitecore.Context.Item == null)
return;
var item = Sitecore.Context.Item;
// must be the right template
if(item.TemplateID.ToString() != "{XXXXXXXXX-XXXX-XXXXXX}")
return;
var basicUrl = LinkManager.GetItemUrl(item);
var response = HttpContext.Current.Response;
response.Redirect(basicUrl + "?sc_camp=XXXXXXX");
}
}
If you're not familiar with adding processors, take a look here.
Per Sitecore support, this is not currently possible. However, I was able to achieve what I wanted by adding a jQuery AJAX call to the campaign URL to the sublayout used by the page type in question. Naturally this only works for clients with JS enabled, but for my purposes, that is not an issue.
<script type="text/javascript">$(function() { $.get('/?sc_camp=[campaignid]'); });</script>
Edited 2014-05-19
I found a way to do this via the Sitecore API. This is rough and needs to check for null values, exceptions, etc., but it does work:
string cookieVal = Request.Cookies["SC_ANALYTICS_GLOBAL_COOKIE"].Value;
List<Guid> guids = new List<Guid>() {
new Guid(cookieVal)
};
Guid automationStateId = new Guid("{24963AE9-1C8C-4E18-8EEE-01BC249D1F1B}");
Guid automationId = Sitecore.Context.Database.GetItem(new Sitecore.Data.ID(automationStateId)).ParentID.ToGuid();
Sitecore.Analytics.Automation.Data.AutomationManager.Provider.CreateAutomationStatesFromBulk(guids, automationId, automationStateId);
I would like to use MVC FoolProof Validation in my MVC 3 application.
I need a Numeric validation and also accepts N/A or n/a. So i decided to create my own custom validation attribute like NumericAllowNAAttribute and add a jQuery validation custom adopter method.
I revisited MVC Foolproof and decided to use that, since it has other helpful method build already. I want those also. Now how can i write a CustomValidationAttribute that works on client side using jQuery validate and Server side?
Searched google on extending MVC Foolproof i didnt get any.
Is any one came across extending or implementing this kind of
validation works in server and client with jQuery validation plugin?
You can extend foolproof MVC by defining a new attribute that inherits ContingentValidationAttribute (or one of the other attributes in foolproof, but continent is pretty close to barebones).
You will need to define the following method overrides.
public override bool IsValid(object value, object dependentValue, object container)
protected override IEnumerable<KeyValuePair<string, object>> GetClientValidationParameters()
public override string ClientTypeName
ClientTypeName string value is used by jquery unobtrusive validation.
Also, be sure to register your adapter with DataAnnotationsModelValidatorProvider (foolproof does it in the constructor for their classes).
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(MyCustomValidationAttribute), typeof(FoolproofValidator));
Once you've defined your server-side validation logic you will need to register with jquery unobtrusive validation on the client-side:
jQuery.validator.addMethod("clienttypenameyouemitontheserver", function(value, element, params) {
// perform your checks here and return true or false
return true;
});
var $Unob = $.validator.unobtrusive;
$Unob.adapters.add("clienttypenameyouemitontheserver", ["param1", "param2", "paramZ"], function (options) {
var value = {
param1: options.params.param1,
param2: options.params.param2,
paramZ: options.params.paramZ
};
setValidationValues(options, "clienttypenameyouemitontheserver", value);
});