Sitecore WFFM custom save action not called - sitecore

I have created a custom save action in WFFM. After updating the save action to have the correct assembly and fully qualified class name I added the save action to a form and attempted to submit. The form submits and presents the thank you message however the issue is that in the class being invoked the execute method of the save action is never called. I am not sure why this is the case any thoughts?
Here is my custom save action and a link to a picture of how I have configured it.
WFFM type
using Sitecore.WFFM.Abstractions.Actions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sitecore.Data;
using Sitecore.WFFM.Abstractions.Shared;
using Sitecore.WFFM.Actions.Base;
using Sitecore.Form.Submit;
namespace Core.Forms {
public class CustomSaveAction: ISaveAction {
//custom parameters
public string SharepointUrl { get; set; }
public string ListId { get; set; }
public string MappedFields { get; set; }
public ID ActionID { get; set; }
public ActionType ActionType
{
get
{
return ActionType.Save;
}
}
public ActionState QueryState(ActionQueryContext queryContext) {
return ActionState.Enabled;
}
public string UniqueKey { get; set; }
public void Execute(ID formId, AdaptedResultList adaptedFields, ActionCallContext actionCallContext = null, params object[] data) {
throw new NotImplementedException();
}
}
}

So I was testing in chrome and getting frustrated so asked another dev on my team to do a build on his machine and see what happened. Low and behold the break point hit. I tried deleting my local copy and repulling from source control and was still running into the same issue. Upon getting frustrated switching browsers somehow managed to make it work. I am guessing that there is something that chrome is caching that it shouldn't be but either way this is what fixed it for me.

Could you update the Execute method and use something like:
public void Execute(ID formid, AdaptedResultList fields, params object[] data)
{
Assert.ArgumentNotNull(fields, "fields");
// Your code here
}

Related

Sum values of detail rows (in extension) and put it in header (in extension)

Acumatica 2021 R1 - Customizations
I am using PXFormula to multiply a qty and cost to create a new extension field in the details of Physical Inventory Review (although I would think the specific screen wouldn’t matter.) That part is working fine. However, I then want to sum that new column’s values into a new extension field in the header. I can't get that part to work.
Here is the relevant detail code:
using PX.Data;
using System;
namespace PX.Objects.IN
{
public class INPIDetailExt : PXCacheExtension<PX.Objects.IN.INPIDetail>
{
#region UsrExtBookCost
[PXDecimal]
[PXUIField(DisplayName="Ext. Book Cost")]
[PXFormula(typeof(Mult<INPIDetail.bookQty, INPIDetail.unitCost>),
typeof(SumCalc<INPIHeaderExt.usrTotalBookCost>))]
public virtual Decimal? UsrExtBookCost { get; set; }
public abstract class usrExtBookCost : PX.Data.BQL.BqlDecimal.Field<usrExtBookCost> { }
#endregion
}
}
Here’s the header code:
using PX.Data;
using System;
namespace PX.Objects.IN
{
public class INPIHeaderExt : PXCacheExtension<PX.Objects.IN.INPIHeader>
{
#region UsrTotalBookCost
[PXDecimal]
[PXUIField(DisplayName="Total Book Cost")]
public virtual Decimal? UsrTotalBookCost { get; set; }
public abstract class usrTotalBookCost : PX.Data.BQL.BqlDecimal.Field<usrTotalBookCost> { }
#endregion
}
}
I feel it has something to do with the fact that these are extensions and that somehow the PXParent that is called in INPIDetail does not cover these extension.
Any suggestions would be appreciated.
By any chance are you calling the PXFormulaAttribute.CalcAggregate in the row selected event of the INPIHeader. This should force the SumCalc to recalculate and update your value
PXFormulaAttribute.CalcAggregate<INPIDetailExt.usrExtBookCost>(DetailView.Cache, e.Row);

How to send a property as a string in RestEasy response?

I have a class called Product which has a property called id of type long. Below is the class
public class Product {
private long id;
}
The value of id is beyond the value which javascript can handle. I realized this after seeing the below link
Parse json in javascript - long numbers get rounded
I dont want to declare the field as String in the domain class. But I want to say to RestEasy that it has to send the value as a string in the json response.
How can I do this? I dont want to use any third party api. Is it possible in RestEasy. I have gone through the documentation but did not find any such annotation or may be I did not go through the documentation properly.
Can anyone please help. Thanks all in advance.
If you are using Jackson as JSON Serializer you can extend the JacksonJsonProvider:
#Provider
public class JsonProvider extends org.codehaus.jackson.JacksonJsonProvider {
public JsonProvider() {
ObjectMapper objectMapper = locateMapper(ObjectMapper.class, MediaType.APPLICATION_JSON_TYPE);
objectMapper.configure(org.codehaus.jackson.JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, true);
}
}
If you are using Jettison you can register a custom XmlAdapter:
public class LongAdapter extends XmlAdapter<String, Long> {
#Override
public String marshal(Long id) throws Exception {
if (id == null) {
return "";
}
return id.toString();
}
#Override
public Long unmarshal(String id) throws Exception {
return Long.parseLong(id);
}
}

Getting an Internal Link with Glass.Mapper

I've got an Internal Link set up in Sitecore, and I'm trying to map the field using Glass.Mapper, but it just keeps coming back empty, and I'm not sure what I'm doing wrong.
The template in Sitecore is pretty simple:
The Source of the link is set to a folder that only allows content based on the 'System' template to be created.
In my code, I have an object set up:
namespace Playground.GlassObjects
{
public partial class Status
{
public virtual string Description { get; set; }
public virtual string StatusCode { get; set; }
public virtual Glass.Mapper.Sc.Fields.Link System { get; set; }
}
}
Which is being used basically like this:
public void DoStuff(Sitecore.Data.Items.Item item)
{
var status = item.GlassCast<Status>();
this.DoOtherStuff(status);
}
What I'm running into is glassObj.Description, and glassObj.StatusCode are being wired up exactly like I want/expect, but glassObj.System is not.
Can anyone tell me what I'm doing wrong here? I'm at a loss right now, with all the magic that's going on behind the scenes.
The Glass.Mapper.Sc.Fields.Link class is designed to work with the General Link field. The internal link field stores values as paths e.g /sitecore/content/home/events. This means it isn't compatible with the Link class.
Instead you should map it to another class you have created.
public partial class Status
{
public virtual string Description { get; set; }
public virtual string StatusCode { get; set; }
public virtual MySystem System { get; set; }
}
public class MySystem{
public virtual string Url { get; set; }
public virtual string MyField { get; set; }
}
Fast forward to 2022 Internal Link field seems to be working with Glassmapper without any extra effort. All you have to do is add Internal Link case to GlassGenerator.tt file on the project where you will generate the template.
This will ensure your model will have Link field like this:
[SitecoreField(FieldId = "{D2CF138A-0A1C-4766-B250-F56E9458B624}")]
Link InternalLinkField{ get; set; }
It will have some info populated and most of the other properties will be null. The ones that will help you are:
Url (full path to the internal link item)
TargetId (ID of the internal link item)
Here are the available properties:
There is an alternative to that, you can get the link from fields like this:
yourGlassItem.Item.Fields["InternalLinkFieldName"]
You will get the entire Internal link Item. You can use Value or InheritedValue property to get the path of the linked item.

many-to-one ForeignKeys in SQL CE db developed with EF Code First

This is my first foray in either SQL CE or EF, so I may have a lot of misunderstandings. I've searched a lot of blog entries but still can't seem to get this right.
I have an MVC3 web site for registrations for a race we're running. I have a RaceEvents table, and a Runners table, where each RaceEvent will have many runners registered it for it, i.e., Many-to-One. Here are the POCO's with extraneous data stripped out:
public class RaceEvent
{
[Required]
public int Id { get; set; }
public virtual ICollection<Runner> Runners { get; set; }
}
public class Runner
{
[Required]
public int Id { get; set; }
[Required]
public int RaceEventId { get; set;}
[ForeignKey("RaceEventId")]
public RaceEvent RaceEvent { get; set; }
}
Which, as much as I can figure out, ought to work. As I understand it, it should figure out by convention that RaceEventId is a foreign key to RaceEvents. And if that's not good enough, I'm telling it with the ForeignKey attribute.
However, it doesn't seem to be working. Whenever I insert a new runner, it is also inserting a new entry in the RaceEvents table. And when I look at the table diagram in ServerExplorer, it shows two gold keys at the top of the Runners table diagram, one for Id, identified in the properties as a PrimaryKey, and the other for RaceEventId, not identified as a PrimaryKey, but indicated in the properties to be for table Runners, rather than for table RaceEvents. I would expect a gold key for Id, but a silver ForeignKey for RaceEventId.
FWIW, I don't really care about the ICollection in the RaceEvent, but the blog entries all seemed to imply that it was necessary.
Can anybody help me get this right?
Thanks.
Ok,
Sorry I did not read your question in enough detail. In our project this is how we would represent what your doing. I looked in SSMS and it is not showing said grey key, but it does not create a race event every time you add a runner. Although you do need to make sure when you create a runner that you set the race event property.
public class DB : DbContext
{
public DB()
: base("Data Source=(local);Initial Catalog=DB;Integrated Security=True")
{
}
public IDbSet<Runner> Runners { get; set; }
public IDbSet<RaceEvent> RaceEvents { get; set; }
}
public class RaceEvent
{
[Key]
public int RaceEventID { get; set; }
}
public class Runner
{
[Key]
public int RunnerID { get; set; }
[Required]
public virtual RaceEvent RaceEvent { get; set; }
}
Any question let me know.
You need to override the model creating in the DbContext. Below is a sample for AnsNet_User & AspNet_Roles N:N relationship
protected override void OnModelCreating(DbModelBuilder dbModelBuilder)
{
dbModelBuilder.Entity<aspnet_Users>().HasMany(a => a.aspnet_Roles).WithMany(b =>
b.aspnet_Users).Map(
m =>
{
m.MapLeftKey("UserId");
m.MapRightKey("RoleId");
m.ToTable("aspnet_UsersInRoles");
});
base.OnModelCreating(dbModelBuilder);
}

How do I unit test routes for web forms?

I have a web form such as mysite.com/list.aspx?state=florida&city=miami that I want users to browse using mysite.com/florida/miami/ and I'm using routing to do so. Then instead of using query string parameters, I end up having to use HttpContext.Current.Items[key] to retrieve the values on my list.aspx page. I have included the code below.
I would like to know what the best practices are to unit test this. Also, is there a better way to implement this without changing my code on the list.aspx page?
Code:
Sample of my Global.asax file:
protected void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.Add(new Route("{state}", new CustomRouteHandler("/list.aspx")));
routes.Add(new Route("{state}/{city}", new CustomRouteHandler("/list.aspx")));
}
Sample of the CustomerRouteHandler:
public class CustomRouteHandler : IRouteHandler
{
public CustomRouteHandler(string virtualPath)
{
this.VirtualPath = virtualPath;
}
public string VirtualPath { get; private set; }
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
foreach (var urlParm in requestContext.RouteData.Values)
{
requestContext.HttpContext.Items[urlParm.Key] = urlParm.Value;
}
IHttpHandler page = BuildManager.CreateInstanceFromVirtualPath (VirtualPath, typeof(Page)) as IHttpHandler;
return page;
}
}
You could use HttpUnit to test that all the url endpoints work correctly.