I want to verify a class using ConstructorInitializedMemberAssertion and a read-only property CreatedAt that is initialized to a default value inside the constructor:
public class MyClass
{
public MyClass(string name)
{
Name = name;
CreatedAt = DateTime.UtcNow;
}
public string Name { get; private set; }
public DateTime CreatedAt { get; private set; }
}
var fixture = new Fixture();
var ctorAssertion = fixture.Create<ConstructorInitializedMemberAssertion>();
ctorAssertion.Verify(typeof(MyClass));
This test throws the following exception:
AutoFixture.Idioms.ConstructorInitializedMemberException: No constructors with an argument that matches the read-only property 'CreatedAt' were found
I looked in the docs, but did not find any sample like that. I'm rather new with AutoFixture, so I may miss something.
How to exclude it from assertion or is there other way to deal with it?
I have some object like this:
public class ResponseBase
{
public string eventType { get; }
public string eventSourceGuid { get; }
}
public class QueryDevicesResponse : ResponseBase
{
public new static string eventType { get => "queryDevicesResponse"; }
public new string eventSourceGuid { get => "0"; }
public EventData eventData { get; set; }
}
eventType field is static because I'm trying to:
minimize lines of code
use it like "application-wide" string stored (in source code) together with DTO class definition, and use it in some switch and if statements without instantiating QueryDevicesResponse.
When I call:
QueryDevicesResponse queryDevicesResponse = QueryDevicesResponse.Mock();
JsonSerializer.Serialize.JsonSerializer.Serialize(queryDevicesResponse);
I'm getting JSON without eventType field. I guess this is because field is static.
Can I change JsonSerializer behavior to include also static fields?
This is similar question, but this is about Newtonsoft.Json:
Why can't JSON .Net serialize static or const member variables?
Alternatively:
How can I replace static modifier to get similar behavior and keep code small?
I have an array of objects in UI that is being sent to MVC Controller . The Array of objects look like :
`DoorId`,`DoorName` and an array of `Schedules`. `Schedules` array has `ScheduleId` and `ScheduleName`.
Now how to send it to MVC Controller ? So that , every DoorId and it's associated ScheduleId can be extracted separately to form another obeject ?
Presently , I am sending the DoorId Array and the ScheduleId array separately ,
But I do not want to do that . I want to send the entire array itself.
public async Task<ActionResult> AddGroup(string[] DoorIds, string[] scheduleEntity)//AccessGroupEntity entity, string accountId
{
GroupEntity groupEntity = new GroupEntity();
var doorScheduleList = new List<DoorInfoEntity>();
for(int i=0;i< DoorIds.Length;i++)
{
doorScheduleList.Add(new DoorInfoEntity()
{
DoorId = DoorIds[i],
ScheduleId = scheduleEntity[i]
});
}
accessGroupEntity.DoorItems = doorScheduleList;
And then Parse it as Doors[index].DoorId and Doors[index].ScheduleId to form 'DoorInfoEntity` object.
How to do it ?
I tried object[] Doors but it says Object does not contain a definition for DoorId or ScheduleId.
You need an object graph in C# that the modelbinder can bind the posted data to which mimics the object graph you have in your JavaScript. For example:
public class Door
{
public Guid DoorId { get; set; }
public string DoorName { get; set; }
public List<Schedule> Schedules { get; set; }
...
}
public class Schedule
{
public Guid ScheduleId { get; set; }
...
}
Then, you accept the root class as a param in your action:
public async Task<ActionResult> AddGroup(List<Door> doors)
The modelbinder, then, will create the object graph server-side from the posted data.
I'm having a issue restricting what kind of Block to be inserted in a ContentArea. What I want is that the SliderBlock's ContentArea property can only have insertion of a SlideItemBlock.
[ContentType(...)]
public class SlideItemBlock : BlockData
{
[Required]
Display(Name = "Image")]
public virtual string Image { get; set;}
}
[ContentType(...)]
public class SliderBlock : BlockData
{
[Required]
[Display(Name = "Slides")]
public virtual ContentArea Slides { get; set; }
//Should only accept insertion of SlideItemBlock
}
Or is this the wrong way to achive what I'm trying to restrict for the editor to not drag and drop wrong block types?
As of now, I can create a SliderBlock and insert a SlideItemBlocks in it. If I then insert the created SliderBlock in a new SliderBlock I get a forever and ever loop and It breaks the site. This is what I'm trying to control.
If you´re using EPiServer 7.5 restricting which blocks you can use in a content area is built in. For details take a look at this blog post: Restricting the allowed types in a content area.
Code example from the blog post:
[EditorDescriptorRegistration(TargetType = typeof(ContentArea), UIHint = "Gallery")]
public class ImageGalleryEditorDescriptor : EditorDescriptor
{
public ImageGalleryEditorDescriptor()
{
// Setup the types that are allowed to be dragged and dropped into the content
// area; in this case only images are allowed to be added.
AllowedTypes = new Type[] { typeof(IContentImage) };
// Unfortunetly the ContentAreaEditorDescriptor is located in the CMS module
// and thus can not be inherited from; these settings are copied from that
// descriptor. These settings determine which editor and overlay should be
// used by this property in edit mode.
ClientEditingClass = "epi-cms.contentediting.editors.ContentAreaEditor";
OverlayConfiguration.Add("customType", "epi-cms.widget.overlay.ContentArea");
}
}
As of EpiServer 8 theres a new attribute called [AllowedTypes]. This is now the best way of restricting blocks. It overcomes a lot of the limitations of [AvailableContentTypes]. When you drag blocks into a content area the validation actually works.
An example code snippet would be
[AllowedTypes(new []{ typeof(SlideBlock) })]
public virtual ContentArea Slides { get; set; }
Theres a good code example here How To Restrict The Blocks Allowed Within A Content Area Episerver
Also this one on EpiWorld http://world.episerver.com/blogs/Ben-McKernan/Dates/2015/2/the-new-and-improved-allowed-types/
Of you have not upgraded to 7.5 yet as Frederik suggest we have the following attribute we have created to do just this.
using EPiServer.Core;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace xxx.Com.Core.Attributes
{
[AttributeUsage(AttributeTargets.Property)]
public class OurAvailableContentTypesAttribute : ValidationAttribute
{
public Type[] Include { get; set; }
public Type[] Exclude { get; set; }
public override bool IsValid(object value)
{
if (value == null)
{
return true;
}
if (!(value is ContentArea))
{
throw new ValidationException("OurAvailableContentTypesAttribute is intended only for use with ContentArea properties");
}
var contentArea = value as ContentArea;
var notAllowedcontentNames = new List<string>();
if (contentArea != null)
{
if (Include != null)
{
var notAllowedContent = contentArea.Contents.Where(x => !ContainsType(Include, x.GetType()));
if (notAllowedContent.Any())
{
notAllowedcontentNames.AddRange(notAllowedContent.Select(x => string.Format("{0} ({1})", x.Name, x.ContentLink.ID)));
}
}
if (Exclude != null)
{
var notAllowedContent = contentArea.Contents.Where(x => ContainsType(Exclude, x.GetType()));
if (notAllowedContent.Any())
{
notAllowedcontentNames.AddRange(notAllowedContent.Select(x => string.Format("{0} ({1})", x.Name, x.ContentLink.ID)));
}
}
}
if (notAllowedcontentNames.Any())
{
ErrorMessage = "contains invalid content items :";
foreach (var notAllowedcontentName in notAllowedcontentNames)
{
ErrorMessage += " " + notAllowedcontentName + ",";
}
ErrorMessage = ErrorMessage.TrimEnd(',');
return false;
}
return true;
}
private bool ContainsType(Type[] include, Type type)
{
return include.Any(inc => inc.IsAssignableFrom(type));
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var result = base.IsValid(value, validationContext);
if (result != null && !string.IsNullOrEmpty(result.ErrorMessage))
{
result.ErrorMessage = string.Format("{0} {1}", validationContext.DisplayName, ErrorMessage);
}
return result;
}
}
}
the usage of this is then
public class OurBlock : BlockData
{
[CultureSpecific]
[Editable(true)]
[Display(Name = "",
Description = "",
GroupName = SiteConstants.GroupNames.ContentArea,
Order = 1)]
[OurAvailableContentTypes(Include = new[] { typeof(OurImageBlock) })]
public virtual ContentArea ImageContentArea { get; set; }
HTH
Adam
Create a validation class and implement the IValidate interface from EPiServer.validation. The validation of this is kept outside of the PageData and BlockData classes.
This should be what you are looking for
using System.Collections.Generic;
using System.Linq;
using EPiServer.Validation;
public class SliderBlockValidator : IValidate<SliderBlock>
{
public IEnumerable<ValidationError> Validate(SliderBlock instance)
{
var errors = new List<ValidationError>();
if (instance.Slides != null &&
instance.Slides.Contents.Any(x => x.GetType().BaseType != typeof (SlideItemBlock)))
{
errors.Add(new ValidationError()
{
ErrorMessage = "Only SlideItemBlocks are allowed in this area",
PropertyName = "Slides",
Severity = ValidationErrorSeverity.Error,
ValidationType = ValidationErrorType.StorageValidation
});
}
return errors;
}
}
More reading at http://sdkbeta.episerver.com/SDK-html-Container/?path=/SdkDocuments/CMS/7/Knowledge%20Base/Developer%20Guide/Validation/Validation.htm&vppRoot=/SdkDocuments//CMS/7/Knowledge%20Base/Developer%20Guide/
If you have upgraded to EPi 7.5 you can use the AllowedTypes annotation
[AllowedTypes(new [] {typeof(SlideItemBlock)})]
public virtual ContentArea Slides { get; set; }
I am unaware if you are able to customize any messages using the later solution. There are a few known limitations
Restriction does not work for overlays when editing on page. This is a bug that has been fixed and will be released in a patch in a few weeks.
No server validation. Currently, the attribute only adds restriction in the UI. We hope to be able to add support for server validation soon which would also give the posibility validate your custom properties.
No validation when creating local blocks in content areas. If you use the new feature to add local blocks to a content area, there is currently no filtering of the content types when you create your new block.
Read more at http://world.episerver.com/Blogs/Linus-Ekstrom/Dates/2013/12/Restriction-of-content-types-in-properties/
All in all the first solution is currently the better one.
You can add a validation attribute to the content area property to restrict the allowed block types.
See this link for a detailed example.
Then using the AvailableContentTypes attribute you can restrict to only allow SlideItemBlock types.
[Required]
[Display(Name = "Slides")]
[AvailableContentTypes(Include = new []{typeof(SlideItemBlock)})]
public virtual ContentArea Slides { get; set; }
I have a very simple server model that includes a parent entity with a [Composition] list of child entities. In my client, I have 2 functions. One function removes all the child entities from the parent and the other removes all and also edits a property on the parent entity.
When I simply remove all child entities and SubmitChanges(), all is well.
When I remove all child entities and edit the parent and SubmitChanges(), there are still pending changes (HasChanges == true) when the SubmitChanges() callback is fired.
I am using Silveright 4 RTM and RIA Services 1.0 RTM.
Any ideas what is going on here?
Here are the server entities:
public class RegionDto
{
public RegionDto()
{
Cities = new List<CityDto>();
}
[Key]
public int Id { get; set; }
public string Name { get; set; }
[Include]
[Composition]
[Association("RegionDto_CityDto", "Id", "RegionId")]
public List<CityDto> Cities { get; set; }
}
public class CityDto
{
[Key]
public int Id { get; set; }
public int RegionId { get; set; }
public string Name { get; set; }
}
And here is the client code:
public static class CState
{
private static RegionDomainContext _domainContext;
public static RegionDomainContext DomainContext
{
get
{
if (_domainContext == null)
{
_domainContext = new RegionDomainContext();
}
return _domainContext;
}
}
public static void SaveChanges()
{
DomainContext.SubmitChanges(op =>
{
if (DomainContext.HasChanges && !DomainContext.IsSubmitting)
{
var w = new ChildWindow();
w.Content = "The DomainContext still has unsaved changes.";
w.Show();
}
}, null);
}
}
public partial class MainPage : UserControl
{
private void ClearCitiesEditRegion(object sender, RoutedEventArgs e)
{
var region = (RegionDto)regionList.SelectedItem;
if (region != null)
{
region.Name += "*";
while (region.Cities.Count > 0)
{
region.Cities.Remove(region.Cities.First());
}
CState.SaveChanges();
}
}
private void ClearCities(object sender, RoutedEventArgs e)
{
var region = (RegionDto)regionList.SelectedItem;
if (region != null)
{
while (region.Cities.Count > 0)
{
region.Cities.Remove(region.Cities.First());
}
CState.SaveChanges();
}
}
}
When you run this code the ChildWindow is only shown when you the ClearCitiesEditRegion() method is called. The only difference between this and the ClearCities() method is the line where I edit the region.Name property.
You can also download a sample project that reproduces this here: http://dl.dropbox.com/u/2393192/RIA_Services_Problem.zip
I received an answer to this on the Silverlight forums. Apparently this is a bug in RIA Service 1.0. The following is Matthew's response on the Silverlight forums.
Yes, I've confirmed this is a bug.
Thanks for reporting it and providing
the repro. As you discovered, the bug
will only repro in composition
scenarios where the parent has been
modified in addition to one or more
children. The workaround is to do an
explicit AcceptChanges if the submit
was successful. For example, here is
the code you'd write in a submit
callback:
if (!submitOperation.HasError)
{
((IChangeTracking)ctxt.EntityContainer).AcceptChanges();
}
This will accept all changes and reset
change state correctly.