Unable to evaluate expression in PCLStorage - windows-8

I'm using PCLStorage in my Win8/Wp8 apps, but for simplicity I'll direct my question only for Win8.
I've referenced the PCLStorage package in my Win8 project and also a PCL project. In my PCL project, I'm creating a document management class to handle the saving/retrieving of files.
private IFileSystem LocalFileSystem { get; set; }
protected IFolder RootFolder { get; set; }
protected IFolder RoamingFolder { get; set; }
public DocStorageManager()
{
LocalFileSystem = FileSystem.Current;
RootFolder = LocalFileSystem.LocalStorage;
RoamingFolder = LocalFileSystem.RoamingStorage;
}
When debugging I see that LocalFileSystem gets set to an instance of PCLStorage.WinRTFileSystem. RootFolder and RoamingFolder however show up as Could not evaluate expression.
Now if I go into the Immediate Window and type FileSystem.Current.LocalStorage I get a valid WinRTFolder with a path to my local storage:
FileSystem.Current.LocalStorage
Name = "LocalState"
[PCLStorage.WinRTFolder]: Name = "LocalState"
Name: "LocalState"
Path: "C:\\Users\\myuser\\AppData\\Local\\Packages\\1957d424-34d5-4856-9186-4a64dfaf1ae7_q5jzzq53vdxma\\LocalState"
However I cannot simply assign RootFolder = FileSystem.Current.LocalStorage because it then says Could not evaluate expression again.
It sounds like there is a fundamental behavior I don't understand. How should I structure this to use it as I need to?
many thanks!

Related

Wicket Deployment mode map resources wrong way

I have Page
getRootRequestMapperAsCompound().add(new NoVersionMapper("/card/${cardId}", CardPage.class));.
On this page there is TinyMCE4 editor. Which try to load images using relative path "images/1.jpg"
I've added resource mapping to allow images successfuly loaded.
mountResource("/card/image/${imageId}", imageResourceReference);
In DEVELOPMENT mode everything work nice, image are loaded in to editor, but in DEPLOYMENT mode, Page has been called twice, first time for /card/1 and second time for /card/image/1.jpg.
How to correctly mount resources for DEPLOYMENT mode?
UPDATE look like found the reason
public int getCompatibilityScore(Request request)
{
return 0; // pages always have priority over resources
}
, but then the question is: "Why it is working nice in development mode"?
Update 2 I haven't find better solution then add my own Resource Mapper with overrided getCompatibilityScore()
public class ImageResourceMapper extends ResourceMapper {
private String[] mountSegments;
public ImageResourceMapper(String path, ResourceReference resourceReference) {
super(path, resourceReference);
mountSegments = getMountSegments(path);
}
public ImageResourceMapper(String path, ResourceReference resourceReference, IPageParametersEncoder encoder) {
super(path, resourceReference, encoder);
mountSegments = getMountSegments(path);
}
#Override
public int getCompatibilityScore(Request request) {
if (urlStartsWith(request.getUrl(), mountSegments)) {
return 10;
}
return 0;
}
}

Using a custom RazorViewEngine AND RazorGenerator precompiled views

I am trying to use a custom (derived) RazorViewEngine AND precompiled views using RazorGenerator.
Some context:
We have a base product that we use for multiple client implementations. With that we have a core set of base views. Most of the views work most of the time. Right now we end up copying existing views for each new solution and modifying as needed. This ends up with 95% of the views being the same between clients and 5% changed.
What I want to do take a base set of views, compile them into a DLL and re-use it across clients. So far I have that working well using RazorGenerator.
Now the next step is to allow for customization (overrides) of views. There is a caveat though. Our application has two "modes" that a user is in. The mode they are in could require a different view.
I have created a derived class from the RazorGeneratorView. This view basically inspects the "OrderingMode" from a UserProfile object that Autofac resolves. Based on the mode - the Path Locator is replaced for the view resolution.
The idea being individual client applications will attempt to resolve the view first in the traditional Views folder. Only I am adding in a sub-directory of Views/{OrderingMode}/{Controller}/{View}.cshtml.
If the view is not found - then it will look in the compiled library (the core views).
This allows me to override individual views / partials as need be for clients.
public PosViewEngine() : base()
{
//{0} = View Name
//{1} = ControllerName
//{2} = Area Name
AreaViewLocationFormats = new[]
{
//First look in the hosting application area folder / Views / ordering type
//Areas/{AreaName}/{OrderType}/{ControllerName}/{ViewName}.cshtml
"Areas/{2}/Views/%1/{1}/{0}.cshtml",
//Next look in the hosting application area folder / Views / ordering type / Shared
//Areas/{AreaName}/{OrderType}/{ControllerName}/{ViewName}.cshtml
"Areas/{2}/Views/%1/Shared/(0}.cshtml",
//Finally look in the IMS.POS.Web.Views.Core assembly
"Areas/{2}/Views/{1}/{0}.cshtml"
};
//Same format logic
AreaMasterLocationFormats = AreaViewLocationFormats;
AreaPartialViewLocationFormats = new[]
{
//First look in the hosting application area folder / Views / ordering type
//Areas/{AreaName}/{OrderType}/{ControllerName}/Partials/{PartialViewName}.cshtml
"Areas/{2}/Views/%1/{1}/Paritals/{0}.cshtml",
//Next look in the hosting application area folder / Views / ordering type / Shared
//Areas/{AreaName}/{OrderType}/{ControllerName}/{ViewName}.cshtml
"Areas/{2}/Views/%1/Shared/(0}.cshtml",
//Finally look in the IMS.POS.Web.Views.Core
"Areas/{2}/Views/{1}/{0}.cshtml"
};
ViewLocationFormats = new[]
{
"Views/%1/{1}/{0}.cshtml",
"Views/%1/Shared/{0}.cshtml",
"Views/{1}/{0}.cshtml",
"Views/Shared/{0}.cshtml"
};
MasterLocationFormats = ViewLocationFormats;
PartialViewLocationFormats = new[]
{
"Views/%1/{1}/Partials/{0}.cshtml",
"Views/%1/Shared/{0}.cshtml",
"Views/{1}/Partials/{0}.cshtml",
"Views/Shared/{0}.cshtml"
};
}
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
return base.CreatePartialView(controllerContext, partialPath.ReplaceOrderType(CurrentOrderingMode()));
}
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
OrderType orderType = CurrentOrderingMode();
return base.CreateView(controllerContext, viewPath.ReplaceOrderType(orderType), masterPath.ReplaceOrderType(orderType));
}
protected override bool FileExists(ControllerContext controllerContext, string virtualPath)
{
return base.FileExists(controllerContext, virtualPath.Replace("%1/",string.Empty));
}
private OrderType CurrentOrderingMode()
{
OrderType result;
_profileService = DependencyResolver.Current.GetService<IUserProfileService>();
if (_profileService == null || _profileService.OrderingType == 0)
{
IApplicationSettingService settingService =
DependencyResolver.Current.GetService<IApplicationSettingService>();
result =
settingService.GetApplicationSetting(ApplicationSettings.DefaultOrderingMode)
.ToEnumTypeOf<OrderType>();
}
else
{
result = _profileService.OrderingType;
}
return result;
}
}
Here is the StartUp class RazorGenerator uses to Register the ViewEngine.
public static class RazorGeneratorMvcStart
{
public static void Start()
{
var engine = new PrecompiledMvcEngine(typeof(RazorGeneratorMvcStart).Assembly)
{
UsePhysicalViewsIfNewer = HttpContext.Current.Request.IsLocal
};
ViewEngines.Engines.Insert(0, engine);
// StartPage lookups are done by WebPages.
VirtualPathFactoryManager.RegisterVirtualPathFactory(engine);
}
}
The problem is:
This code is executed last (after I register the PosViewEngine) and it inserts the engine at the first position (meaning this is the engine that gets resolved 1st when serving up responses). This ends up finding a view - it is the core view.
If I change the code in the StartUp to Register my custom view engine first first and then the RazorGenerator engine
public static void Start()
{
var engine = new PrecompiledMvcEngine(typeof(RazorGeneratorMvcStart).Assembly)
{
UsePhysicalViewsIfNewer = HttpContext.Current.Request.IsLocal
};
ViewEngines.Engines.Clear();
ViewEngines.Engines.Insert(0, new PosViewEngine());
ViewEngines.Engines.Insert(1, engine);
// StartPage lookups are done by WebPages.
VirtualPathFactoryManager.RegisterVirtualPathFactory(engine);
}
I end up with an exception on the FileExists(ControllerContext controllerContext, string virtualPath) method - "The relative virtual path 'Views/Account/LogOn.cshtml' is not allowed here."
It obviously has something to do with both physical and virtual paths being mixed together.
It looks like someone else was trying to do the same thing here but I didn't see an answer on this.
For anyone else wanting to try this approach I'll post the answer. Basically you need to implement a custom view engine that derives from the PrecompiledMvcEngine found in the RazorGenerator assembly.
public class PosPrecompileEngine : PrecompiledMvcEngine
{
private IUserProfileService _profileService;
public PosPrecompileEngine(Assembly assembly) : base(assembly)
{
LocatorConfig();
}
public PosPrecompileEngine(Assembly assembly, string baseVirtualPath) : base(assembly, baseVirtualPath)
{
LocatorConfig();
}
public PosPrecompileEngine(Assembly assembly, string baseVirtualPath, IViewPageActivator viewPageActivator) : base(assembly, baseVirtualPath, viewPageActivator)
{
LocatorConfig();
}
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
return base.CreatePartialView(controllerContext, partialPath.ReplaceOrderType(CurrentOrderingMode()));
}
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
OrderType orderType = CurrentOrderingMode();
return base.CreateView(controllerContext, viewPath.ReplaceOrderType(orderType), masterPath.ReplaceOrderType(orderType));
}
protected override bool FileExists(ControllerContext controllerContext, string virtualPath)
{
return base.FileExists(controllerContext, virtualPath.ReplaceOrderType(CurrentOrderingMode()));
}
}
In this class - I override the Locator Paths. Because I have the "base" compiled views in another assembly from the web application - we implemented a convention where the view engine will first look in a PosViews/{ordering mode}/{controller}/{view} path in the web application. If a view is not located -then it will look in the traditional /Views/controller/view. The trick here is the later is a virtual path located in another class library.
This allowed us to "override" an existing view for the application.
private void LocatorConfig()
{
//{0} = View Name
//{1} = ControllerName
//{2} = Area Name
AreaViewLocationFormats = new[]
{
//First look in the hosting application area folder / Views / ordering type
//Areas/{AreaName}/{OrderType}/{ControllerName}/{ViewName}.cshtml
"PosAreas/{2}/Views/%1/{1}/{0}.cshtml",
//Next look in the hosting application area folder / Views / ordering type / Shared
//Areas/{AreaName}/{OrderType}/{ControllerName}/{ViewName}.cshtml
"PosAreas/{2}/Views/%1/Shared/(0}.cshtml",
//Next look in the POS Areas Shared
"PosAreas/{2}/Views/Shared/(0}.cshtml",
//Finally look in the IMS.POS.Web.Views.Core assembly
"Areas/{2}/Views/{1}/{0}.cshtml"
};
//Same format logic
AreaMasterLocationFormats = AreaViewLocationFormats;
AreaPartialViewLocationFormats = new[]
{
//First look in the hosting application area folder / Views / ordering type
//Areas/{AreaName}/{OrderType}/{ControllerName}/Partials/{PartialViewName}.cshtml
"PosAreas/{2}/Views/%1/{1}/Partials/{0}.cshtml",
//Next look in the hosting application area folder / Views / ordering type / Shared
//Areas/{AreaName}/{OrderType}/{ControllerName}/{ViewName}.cshtml
"PosAreas/{2}/Views/%1/Shared/(0}.cshtml",
//Next look in the hosting application shared folder
"PosAreas/{2}/Views/Shared/(0}.cshtml",
//Finally look in the IMS.POS.Web.Views.Core
"Areas/{2}/Views/{1}/{0}.cshtml"
};
ViewLocationFormats = new[]
{
"~/PosViews/%1/{1}/{0}.cshtml",
"~/PosViews/%1/Shared/{0}.cshtml",
"~/PosViews/Shared/{0}.cshtml",
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{0}.cshtml"
};
MasterLocationFormats = ViewLocationFormats;
PartialViewLocationFormats = new[]
{
"~/PosViews/%1/{1}/{0}.cshtml",
"~/PosViews/%1/Shared/{0}.cshtml",
"~/PosViews/Shared/{0}.cshtml",
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{0}.cshtml"
};
}
Register this engine in your application start up events.
public static void Configure()
{
var engine = new PosPrecompileEngine(typeof(ViewEngineConfig).Assembly)
{
UsePhysicalViewsIfNewer = true,
PreemptPhysicalFiles = true
};
ViewEngines.Engines.Add(engine);
// StartPage lookups are done by WebPages.
VirtualPathFactoryManager.RegisterVirtualPathFactory(engine);
}
Here is the final key. When RazorGenerator gets installed view NuGet - you end up with this start-up class that will run on startup
[assembly: WebActivatorEx.PostApplicationStartMethod(typeof(Views.Core.RazorGeneratorMvcStart), "Start")]
public static class RazorGeneratorMvcStart
{
public static void Start()
{
var engine = new PrecompiledMvcEngine(typeof(RazorGeneratorMvcStart).Assembly)
{
UsePhysicalViewsIfNewer = true,
PreemptPhysicalFiles = true
};
ViewEngines.Engines.Add(engine);
// StartPage lookups are done by WebPages.
VirtualPathFactoryManager.RegisterVirtualPathFactory(engine);
}
}
By default - RazorGenerator adds ViewEngine to the first in the collection
ViewEngines.Engines.Insert(0,engine);
You need to change that to an add
ViewEngines.Engines.Add(engine);
So it is added to engines last - this way your custom ViewEngine is used FIRST in locating views.
This approach allows you to reuse views in multiple applications while allowing a means to override that view.
This may be overkill for most applications - bust as I mentioned in the question - this is base product that we use to develop multiple client applications. Trying achieve reuse while maintaining a level of flexibility on a per client basis is something we were trying to achieve.

RazorEngine Error trying to send email

I have an MVC 4 application that sends out multiple emails. For example, I have an email template for submitting an order, a template for cancelling an order, etc...
I have an Email Service with multiple methods. My controller calls the Send method which looks like this:
public virtual void Send(List<string> recipients, string subject, string template, object data)
{
...
string html = GetContent(template, data);
...
}
The Send method calls GetContent, which is the method causing the problem:
private string GetContent(string template, object data)
{
string path = Path.Combine(BaseTemplatePath, string.Format("{0}{1}", template, ".html.cshtml"));
string content = File.ReadAllText(path);
return Engine.Razor.RunCompile(content, "htmlTemplate", null, data);
}
I am receiving the error:
The same key was already used for another template!
In my GetContent method should I add a new parameter for the TemplateKey and use that variable instead of always using htmlTemplate? Then the new order email template could have newOrderKey and CancelOrderKey for the email template being used to cancel an order?
Explanation
This happens because you use the same template key ("htmlTemplate") for multiple different templates.
Note that the way you currently have implemented GetContent you will run into multiple problems:
Even if you use a unique key, for example the template variable, you will trigger the exception when the templates are edited on disk.
Performance: You are reading the template file every time even when the template is already cached.
Solution:
Implement the ITemplateManager interface to manage your templates:
public class MyTemplateManager : ITemplateManager
{
private readonly string baseTemplatePath;
public MyTemplateManager(string basePath) {
baseTemplatePath = basePath;
}
public ITemplateSource Resolve(ITemplateKey key)
{
string template = key.Name;
string path = Path.Combine(baseTemplatePath, string.Format("{0}{1}", template, ".html.cshtml"));
string content = File.ReadAllText(path);
return new LoadedTemplateSource(content, path);
}
public ITemplateKey GetKey(string name, ResolveType resolveType, ITemplateKey context)
{
return new NameOnlyTemplateKey(name, resolveType, context);
}
public void AddDynamic(ITemplateKey key, ITemplateSource source)
{
throw new NotImplementedException("dynamic templates are not supported!");
}
}
Setup on startup:
var config = new TemplateServiceConfiguration();
config.Debug = true;
config.TemplateManager = new MyTemplateManager(BaseTemplatePath);
Engine.Razor = RazorEngineService.Create(config);
And use it:
// You don't really need this method anymore.
private string GetContent(string template, object data)
{
return Engine.Razor.RunCompile(template, null, data);
}
RazorEngine will now fix all the problems mentioned above internally. Notice how it is perfectly fine to use the name of the template as key, if in your scenario the name is all you need to identify a template (otherwise you cannot use NameOnlyTemplateKey and need to provide your own implementation).
Hope this helps.
(Disclaimer: Contributor of RazorEngine)

Creating a new Content Item in the migration with Orchard CMS

Here's my migration code:
public Migrations(IRepository<ProductPartRecord> productPartRepository, IRepository<CategoryPartRecord> categoryPartRepository)
{
_productPartRepository = productPartRepository;
_categoryPartRepository = categoryPartRepository;
}
public int Create() {
ContentDefinitionManager.AlterTypeDefinition("Category", builder => builder
.WithPart("CommonPart")
.WithPart("TitlePart")
.WithPart("AutoroutePart"));
ContentDefinitionManager.AlterTypeDefinition("Category", builder => builder
.WithPart("AutoroutePart", partBuilder => partBuilder
.WithSetting("AutorouteSettings.AllowCustomPattern", "true")
.WithSetting("AutorouteSettings.AutomaticAdjustmentOnEdit", "false")
.WithSetting("AutorouteSettings.PatternDefinitions", "[{Name:'Category Title', Pattern: 'category/{Content.Slug}', Description: 'category/category-title'}]")));
SchemaBuilder.CreateTable("CategoryPartRecord", table => table
.ContentPartRecord()
.Column<string>("Name")
.Column<string>("Description")
.Column<string>("Image")
);
ContentDefinitionManager.AlterTypeDefinition("Category", builder => builder
.WithPart("CategoryPart"));
ContentDefinitionManager.AlterTypeDefinition("Category", builder => builder
.Creatable()
.Draftable());
return 1;
}
public int UpdateFrom1() {
_categoryPartRepository.Create(new CategoryPartRecord { Name = "Category1", Description = "Description1", Image = "Image1" });
return 2;
}
UpdateFrom1 obviously attempts to insert a dummy record, but this causes nHibernate to throw this exception:
"attempted to assign id from null one-to-one property: ContentItemRecord"
The Part Record looks like:
public class CategoryPartRecord : ContentPartRecord {
public CategoryPartRecord()
{
CategoryProducts = new List<CategoryProductRecord>();
}
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual string Image { get; set; }
public virtual IList<CategoryProductRecord> CategoryProducts { get; set; }
}
Any clues as to where I'm going wrong here? Google produced nothing.
Okay, so you are creating a contentpartrecord, not a content item there. What you want is something more along the lines of:
var item = _orchardServices.ContentManager.New("Category").As<CategoryPart>();
item.Name = "Bobs Item"; // Something like that...
item.ContentItem.As<TitlePart>().Title = "Yay a title"; // This syntax may be wrong, I'm very tired
_orchardServices.ContentManager.Create(item);
_orchardServices.ContentManager.Publish(item.ContentItem);
I think that is how you would do it. Maybe you would want to look into creating content items using the import/export module, that is the more common and safe way to do it.
Not sure if the answer from Hazza works. Haven't tried that.
I usually just do this: (But not sure if it's an inferior approach in some way)
var item = _orchardServices.ContentManager.New("Category");
var cpart = item.As<CategoryPart>();
var tpart = item.As<TitlePart>();
cpart.Name = "SomeName";
tpart.Title = "SomeTitle";
_orchardServices.ContentManager.Create(item);
But to address the comment by Lawrence Johnson:
Category in this case is the content item. He is creating a new Category content item, and then extracting the corresponding CategoryPart from it.
If you are getting null when trying to extract the part you're probably missing something.
In order for this to work you need to implement the CategoryPart, CategoryPartRecord, CategoryPartHandler and CategoryPartDriver. (And of course make sure to attach your CategoryPart to you Category content item. Not certain if placement.info is required, but would add it for consistency anyway.)
You can't leave any of these out if you plan to use a Part attached to a content item.
I'm not sure if/how you can create a Part with no content item, but you can create a Record with no part and no content item (Just make sure you don't inherit ContentPartRecord in your record object). If you simply want to add a record with no part or content item, then the code in UpdateFrom1 used by Ben Power would work for creating a record. (But migration part would have to be changed, taking out the content item and part, and manually setting the Id to be a primary key for the record)

Configuring Fault Contract Exception Handlers in Enterprise Library 6 for WCF

How do you map additional properties of an exception to your custom fault contract when using Enterprise Library 6's Exception Handling Application Block?
This article describes the FaultContractPropertyMapping the same way this one does. If you have a fault contract like so:
[DataContract]
public class SalaryCalculationFault
{
[DataMember]
public Guid FaultID { get; set; }
[DataMember]
public string FaultMessage { get; set; }
}
How do you add another property and map it to the original exception? Lets say I want to show the Stored Procedure name to the client using a new property:
[DataMember]
public string StoredProcedureName { get; set; }
I try editing the mapping shown on page 90 of the "Developer's Guide to Microsoft Enterprise Library-Preview.pdf" which can be found here but it does not seem to work. My new mapping looks like this:
var mappings = new NameValueCollection();
mappings.Add("FaultID", "{Guid}");
mappings.Add("FaultMessage", "{Message}");
mappings.Add("StoredProcedureName", "{Procedure}"); //SqlException has a Procedure property
And here is the policy.
var testPolicy = new List<ExceptionPolicyEntry>
{
{
new ExceptionPolicyEntry(typeof(SqlException),
PostHandlingAction.ThrowNewException,
new IExceptionHandler[]
{
new FaultContractExceptionHandler(typeof(SalaryCalculationFault), mappings)
})
}
};
var policies = new List<ExceptionPolicyDefinition>();
policies.Add(new ExceptionPolicyDefinition(
"TestPolicy", testPolicy));
exManager = new ExceptionManager(policies);
ExceptionPolicy.Reset();
ExceptionPolicy.SetExceptionManager(exManager);
When I do this and catch the FaultException on the client and inspect it, the StoredProcedureName is always empty. Why doesn't it map from the SqlException to the new property in my fault exception?
It turns out you shouldn't actually place the code you expect an exception for inside of the ExceptionManager.Processs() method. I was doing this before:
exManager.Process(() => wimDAL.Execute_NonQueryNoReturn(sc), "TestPolicy");
Insead, just execute the code as normal.
wimDAL.Execute_NonQueryNoReturn(sc);
This does not follow what the "Developer's Guide to Microsoft Enterprise Library-Preview.pdf" says but I guess the documentation is still a work in progress. I hope this helps someone else.