Create an Alias from the Recipe in Orchard - orchardcms

I want to create the following Alias from the recipe.
How is this achieved?

I have created this class to add a command for Orchard to create a new alias from command line or recipe:
using Orchard;
using Orchard.Alias;
using Orchard.Commands;
using System;
using Orchard.Environment;
using System.Linq;
namespace Contrib.Foundation.Common.Commands
{
public class AliasCommands : DefaultOrchardCommandHandler
{
private readonly Work<WorkContext> _workContext;
private readonly IAliasService _aliasService;
public AliasCommands(Work<WorkContext> workContext, IAliasService aliasService,
IOrchardServices orchardServices)
{
_workContext = workContext;
_aliasService = aliasService;
Services = orchardServices;
}
public IOrchardServices Services { get; private set; }
[OrchardSwitch]
public string AliasPath { get; set; }
[OrchardSwitch]
public string RoutePath { get; set; }
[CommandName("alias add")]
[CommandHelp("alias add /AliasPath:<alias-path> /RoutePath:<route-path>\r\n\t" + "Add a new alias")]
[OrchardSwitches("AliasPath,RoutePath")]
public void Add()
{
AliasPath = AliasPath.TrimStart('/', '\\');
if (String.IsNullOrWhiteSpace(AliasPath))
{
AliasPath = "/";
}
if (String.IsNullOrWhiteSpace(RoutePath))
{
Context.Output.WriteLine(T("Route can't be empty"));
return;
}
if (CheckAndWarnIfAliasExists(AliasPath))
{
Context.Output.WriteLine(T("Alias already exist"));
return;
}
try
{
_aliasService.Set(AliasPath, RoutePath, "Custom");
}
catch (Exception ex)
{
Services.TransactionManager.Cancel();
Context.Output.WriteLine(T("An error occured while creating the alias {0}: {1}. Please check the values are correct.", AliasPath, ex.Message));
return;
}
Context.Output.WriteLine(T("Alias {0} created.", AliasPath));
}
private string GetExistingPathForAlias(string aliasPath)
{
var routeValues = _aliasService.Get(aliasPath.TrimStart('/', '\\'));
if (routeValues == null) return null;
return _aliasService.LookupVirtualPaths(routeValues, _workContext.Value.HttpContext)
.Select(vpd => vpd.VirtualPath)
.FirstOrDefault();
}
private bool CheckAndWarnIfAliasExists(string aliasPath)
{
var routePath = GetExistingPathForAlias(aliasPath);
if (routePath == null) return false;
return true;
}
}
}
You can use it in a recipe like this:
<Command>
alias add /AliasPath:"/" /RoutePath:"mycontroller"
</Command>
Put the class inside your module and reference Orchard.Alias

Related

Orchard ICustomVirtualPathProvider

I am trying to register a ICustomVirtualPathProvider in one of my modules. This is what I am trying to use:
public class AzureVirtualPathProvider : VirtualPathProvider, ICustomVirtualPathProvider
{
public IStaticDataStorageProvider StaticDataStorageProvider { get; set; }
public VirtualPathProvider Instance
{
get
{
return this;
}
}
public AzureVirtualPathProvider(IStaticDataStorageProvider staticDataStorageProvider)
{
StaticDataStorageProvider = staticDataStorageProvider;
}
public override bool FileExists(string virtualPath)
{
if (!virtualPath.Contains("StaticData")) return base.FileExists(virtualPath);
return true;
}
public override VirtualFile GetFile(string virtualPath)
{
if (!virtualPath.Contains("StaticData") || !StaticDataStorageProvider.IsCloud()) return base.GetFile(virtualPath);
return new CustomVirtualFile(StaticDataStorageProvider, virtualPath);
}
}
so in Module.Load I am setting:
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<AzureVirtualPathProvider>().PropertiesAutowired().As<ICustomVirtualPathProvider>();
}
but this has not been picked up when Orchard calls this line in OrchardStartup.cs (in Orchard.Framework)
if (HostingEnvironment.IsHosted) {
foreach (var vpp in container.Resolve<IEnumerable<ICustomVirtualPathProvider>>()) {
HostingEnvironment.RegisterVirtualPathProvider(vpp.Instance);
}
}
I haver tried calling HostingEnvironment.RegisterVirtualPathProvider directly thus:
HostingEnvironment.RegisterVirtualPathProvider(new AzureVirtualPathProvider());
and tried to inject the dependency using property injecction:
builder.Register(c => new AzureVirtualPathProvider { StaticDataStorageProvider = c.Resolve<IStaticDataStorageProvider>() });
however the value for StaticDataStorageProvider is always null when AzureVirtualPathProvider is run.
I have tried moving AzureVirtualPathProvider to OrchardFramework but then it does not resolve StaticDataStorageProvider.
How do I get Orchard to load my CustomVirtualPathProvider?
In the end I did this:
public class OrchardShellEvents : IOrchardShellEvents
{
readonly ICustomVirtualPathProvider _customVirtualPathProvider;
public OrchardShellEvents(ICustomVirtualPathProvider customVirtualPathProvider)
{
_customVirtualPathProvider = customVirtualPathProvider;
}
public void Activated()
{
HostingEnvironment.RegisterVirtualPathProvider(_customVirtualPathProvider.Instance);
}
public void Terminating()
{
}
}
I don't know if this is the best solution but it worked and might help someone else.

MEF's GetExports<T, TMetadataView>() fails to find composed parts in the CompositionContainer

When attempting to load an instantiated export with GetExports() (using a LINQ query described below), the method returns null. I notice that when I call GetExports without the LINQ query, the return value is Count: 0. This would indicate to me that MEF is failing to find any exports that have been composed in the container. I can see the ExportDefinition, however, when looking at Container.Catalog.Parts.ExportDefinitions. Any ideas on where I am going wrong? Everything up until the query seems to be working fine.
I have the following contract and metadata view declared and implemented:
public interface IMap
{
void Init();
int ParseData();
}
public interface IMapMetadata
{
string MapName { get; }
string DocumentType { get; }
}
[Export(typeof(IMap))]
[ExportMetadata("MapName", "Map")]
public class Map
{
public Map()
{
}
}
I am using the following code to load a directory that contains DLLs that satisfy this contract with:
public void LoadByDirectory(string zPath)
{
try
{
_catalog.Catalogs.Add(new DirectoryCatalog(zPath));
}
catch (Exception e)
{
String zErrMess = e.Message;
}
}
Using a LINQ query to get an export:
public IMap GetMapInstance(string zMapName)
{
IMap ndeMap;
_container = new CompositionContainer(_catalog);
_container.ComposeParts(this);
try
{
ndeMap = _container.GetExports<IMap, IMapMetadata>()
.Where(p => p.Metadata.MapName.Equals(zMapName))
.Select(p => p.Value)
.FirstOrDefault();
}
catch (Exception ex)
{
throw new Exception("Failed to load map " + zMapName + ": " + ex.Message, ex);
}
return ndeMap;
}
Calling the above method like this:
IMap map = mapFactory.GetMapInstance("Map");
returns null.
UPDATED
In addition to the answer below, I was forgetting to declare the interface on the map class, this resolves the issue (note I removed the DocumentType property):
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class MapExportAttribute : ExportAttribute, IMapMetadata
{
public MapExportAttribute()
: base(typeof(IMap))
{
}
public string MapName { get; set; }
}
[MapExport(MapName="Map")]
public class Map : IMap
{
public Map()
{
}
public void Init()
{
throw new NotImplementedException();
}
public int ParseData()
{
throw new NotImplementedException();
}
}
It looks like you're missing the DocumentType meta-data on your export:
[Export(typeof(IMap))]
[ExportMetadata("MapName", "Map")]
[ExportMetadata("DocumentType", "???")]
public class Map
{
}
The simplest way to ensure you specify the correct meta-data is a custom export attribute:
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class MapExportAttribute : ExportAttribute, IMapMetadata
{
public MapExportAttribute() : base(typeof(IMap))
{
}
public string MapName { get; set; }
public string DocumentType { get; set; }
}
[MapExport(MapName = "Map")]
public class Map
{
}

ServiceStack empty metadata

Seeing a strange problem, getting empty metata pages for xml,json and jvs.
Using the following command line app. How does one debug these issues?
namespace ConsoleApplication2
{
public struct NativeUser
{
public int login;
public string group;
public string name;
}
[DataContract]
public class User
{
private NativeUser _native;
public User() { }
public User(NativeUser native)
{
_native = native;
}
public static implicit operator NativeUser(User user)
{
return user._native;
}
public static implicit operator User(NativeUser native)
{
return new User(native);
}
// ReSharper disable InconsistentNaming
[DataMember]
public int login
{
get { return _native.login; }
set { _native.login = value; }
}
[DataMember]
public string group
{
get { return _native.group; }
set { _native.group = value; }
}
[DataMember]
public string name
{
get { return _native.name; }
set { _native.name = value; }
}
}
[Description("GET account, all or by list of groups or by list of logins")]
[Route("/accounts/{groups}", "GET")]
[Route("/accounts/{logins}", "GET")]
[Route("/accounts/", "GET")]
public class Accounts : IReturn<User[]>
{
public string[] groups { set; get; }
public int[] logins { set; get; }
public Accounts() { }
public Accounts(params int[] logins)
{
this.logins = logins;
}
public Accounts(params string[] groups)
{
this.groups = groups;
}
}
public class Host : AppHostHttpListenerBase
{
public Host() : base("Test",
typeof(Accounts).Assembly)
{
}
public override void Configure(Funq.Container container)
{
}
}
public class Servce : IService
{
public object Get(Accounts request)
{
return new List<User>(){new User(new NativeUser())};
}
}
class Program
{
static void Main(string[] args)
{
var host = new Host();
host.Init();
host.Start("http://+:12345/");
global::System.Console.ReadLine();
}
}
}
Nm, found the bug :
public class Accounts : IReturn<User[]>
needs to be
public class Accounts : IReturn<List<User>>
Another very note worthy thing: All DTO's and objects being passed back and fourth in the DTO's require an empty constructor in order for the metata data to be properly generated.
Not sure if this is by design or a bug

Using Three20 TTPhotoViewController with MonoTouch

I'm trying to use the Three20 TTPhotoViewController with MonoTouch. I've derived FacebookPhoto from TTPhoto and FacebookPhotoSource from TTPhotoSource and am now trying to invoke the TTPhotoViewController but I get the following exception when pushing the view controller:
Objective-C exception thrown. Name: NSInvalidArgumentException Reason: * -[NSPlaceholderString initWithFormat:locale:arguments:]: nil argument
I noticed that the monotouch bindings in this github project: https://github.com/mono/monotouch-bindings/tree/492f68c3c2007f0638452cc8a5a762556db224ba/Three20/binding were missing the photoAtIndex binding, so I added that and recompiled them, but I haven't been able to figure out why I am getting this exception.
Here is how I'm invoking the TTPhotoViewController:
List<Photo> photoList = FacebookGraphApi.Instance.GetAlbumPhotos(album.id);
List<FacebookPhoto> fbPhotoList = photoList.Select(x => new FacebookPhoto(x)).ToList();
var photos = new TTPhotoViewController();
photos.PhotoSource = new FacebookPhotoSource(fbPhotoList);
NavController.PushViewController(photos, true);
Here is the definition of the TTPhotoSource
class FacebookPhotoSource : TTPhotoSource
{
List<FacebookPhoto> _photoList;
public FacebookPhotoSource (List<FacebookPhoto> photoList)
{
_photoList = photoList;
int i = 0;
foreach (FacebookPhoto photo in photoList) {
photo.PhotoSource = this;
photo.Index = i++;
}
}
public override string Title {
get {
return "Facebook Photos";
}
set {
throw new NotImplementedException();
}
}
public override int NumberOfPhotos {
get {
return _photoList.Count;
}
}
public override int MaxPhotoIndex {
get {
return _photoList.Count -1;
}
}
public override TTPhoto PhotoAtIndex(int photoIndex)
{
return _photoList[photoIndex];
}
}
and here is the definition of the FacebookPhoto:
class FacebookPhoto : TTPhoto
{
Photo _photo;
public FacebookPhoto(Photo photo)
{
_photo = photo;
}
public override string Caption {
get {
if(_photo.name == null)
return "";
return _photo.name;
}
set {
throw new NotImplementedException();
}
}
public override TTPhotoSource PhotoSource { get; set; }
public override int Index { get; set; }
public override SizeF Size {
get {
return new SizeF(_photo.width, _photo.height);
}
set {
throw new NotImplementedException();
}
}
public override string URLForVersion (int version)
{
switch (version) {
case 4:
return _photo.picture;
default:
return _photo.source;
}
}
}

Orchard Content Type is null

i am new in orchard module development.i create a module.when i try to save data.
i use this code fore save data
public ActionResult Create(FormCollection input)
{
var product = contentManager.New<ProductPart>("Product");
product.EmployeeName = input["EmployeeName"];
product.EmployeeFathersName = input["EmployeeFathersName"];
product.DOB = Convert.ToDateTime(input["DOB"]);
product.Email = input["Email"];
product.Address = input["Address"];
product.JoiningDate = Convert.ToDateTime(input["JoiningDate"]);
if (!ModelState.IsValid)
{
return View(product);
}
contentManager.Create(product);
return RedirectToAction("Index");
}
this class i use in Model
public class ProductRecord:ContentPartRecord
{
public virtual string EmployeeName { get; set; }
public virtual string EmployeeFathersName { get; set; }
public virtual DateTime DOB { get; set; }
public virtual string Email { get; set; }
public virtual string Address { get; set; }
public virtual DateTime JoiningDate { get; set; }
}
public class ProductPart : ContentPart<ProductRecord>
{
/*
public int Id
{
get { return Record.Id; }
set{Record.Id = value;}
}
*/
[Required]
public string EmployeeName
{
get { return Record.EmployeeName; }
set { Record.EmployeeName = value; }
}
[Required]
public string EmployeeFathersName
{
get { return Record.EmployeeFathersName; }
set { Record.EmployeeFathersName = value; }
}
[Required]
public DateTime DOB
{
get { return Record.DOB; }
set { Record.DOB = value; }
}
[Required]
public string Email
{
get { return Record.Email; }
set { Record.Email = value; }
}
[Required]
public string Address
{
get { return Record.Address; }
set { Record.Address = value; }
}
[Required]
public DateTime JoiningDate
{
get { return Record.JoiningDate;}
set { Record.JoiningDate = value; }
}
}
i use content type "Product" but when it goes orchard ContentCreateExtension in belows method
public static T New<T>(this IContentManager manager, string contentType) where T : class, IContent {
var contentItem = manager.New(contentType);
if (contentItem == null)
return null;
var part = contentItem.Get<T>();
if (part == null)
throw new InvalidCastException();
return part;
}
here i face var part is null that means it content part is null.
please help me....
Have you setup your migrations class?
i.e.
public class Migrations : DataMigrationImpl {
public int Create() {
SchemaBuilder.CreateTable("ProductRecord",
table => table
.ContentPartRecord()
.COLUMNS NEED TO BE SPECIFIED
);
ContentDefinitionManager.AlterTypeDefinition("Forum",
cfg => cfg
.WithPart("ProductPart")
.WithPart("CommonPart")
);
Also have you setup your repository?
i.e.
public class ProductPartHandler : ContentHandler {
public ProductPartHandler(IRepository<ProductPartRecord> repository) {
Filters.Add(StorageFilter.For(repository));
}
In addition to the Nicholas answer, I want to mention, that missing driver for the ProductPart can cause such error. Make sure, that you have at least empty driver defined.
public class ProductPartDriver : ContentPartDriver<ProductPart> {}
Just went through a similar situation, be sure that the handler class is declared as public.

Resources