How can i use engine object in my console application - tridion

"How can i use engine in my console application"
I shouldn't use the ITemplate-interface and Transform-Method.
I am using Tridion 2011
Could anyone please suggest me.

You can't. The Engine class is part of the TOM.NET and that API is explicitly reserved for use in:
Template Building Blocks
Event Handlers
For all other cases (such as console applications) you should use the Core Service.
There are many good questions (and articles on other web sites) already:
https://stackoverflow.com/search?q=%5Btridion%5D+core+service
http://www.google.com/#q=tridion+core+service
If you get stuck along the way, show us the relevant code+configuration you have and what error message your get (or at what step you are stuck) and we'll try to help from there.

From a console application you should use the Core Service. I wrote a small example using the Core Service to search for items in the content manager.
Console.WriteLine("FullTextQuery:");
var fullTextQuery = Console.ReadLine();
if (String.IsNullOrWhiteSpace(fullTextQuery) || fullTextQuery.Equals(":q", StringComparison.OrdinalIgnoreCase))
{
break;
}
Console.WriteLine("SearchIn IdRef:");
var searchInIdRef = Console.ReadLine();
var queryData = new SearchQueryData
{
FullTextQuery = fullTextQuery,
SearchIn = new LinkToIdentifiableObjectData
{
IdRef = searchInIdRef
}
};
var results = coreServiceClient.GetSearchResults(queryData);
results.ToList().ForEach(result => Console.WriteLine("{0} ({1})", result.Title, result.Id));
Add a reference to Tridion.ContentManager.CoreService.Client to your Visual Studio Project.
Code of the Core Service Client Provider:
public interface ICoreServiceProvider
{
CoreServiceClient GetCoreServiceClient();
}
public class CoreServiceDefaultProvider : ICoreServiceProvider
{
private CoreServiceClient _client;
public CoreServiceClient GetCoreServiceClient()
{
return _client ?? (_client = new CoreServiceClient());
}
}
And the client itself:
public class CoreServiceClient : IDisposable
{
public SessionAwareCoreServiceClient ProxyClient;
private const string DefaultEndpointName = "netTcp_2011";
public CoreServiceClient(string endPointName)
{
if(string.IsNullOrWhiteSpace(endPointName))
{
throw new ArgumentNullException("endPointName", "EndPointName is not specified.");
}
ProxyClient = new SessionAwareCoreServiceClient(endPointName);
}
public CoreServiceClient() : this(DefaultEndpointName) { }
public string GetApiVersionNumber()
{
return ProxyClient.GetApiVersion();
}
public IdentifiableObjectData[] GetSearchResults(SearchQueryData filter)
{
return ProxyClient.GetSearchResults(filter);
}
public IdentifiableObjectData Read(string id)
{
return ProxyClient.Read(id, new ReadOptions());
}
public ApplicationData ReadApplicationData(string subjectId, string applicationId)
{
return ProxyClient.ReadApplicationData(subjectId, applicationId);
}
public void Dispose()
{
if (ProxyClient.State == CommunicationState.Faulted)
{
ProxyClient.Abort();
}
else
{
ProxyClient.Close();
}
}
}
When you want to perform CRUD actions through the core service you can implement the following methods in the client:
public IdentifiableObjectData CreateItem(IdentifiableObjectData data)
{
data = ProxyClient.Create(data, new ReadOptions());
return data;
}
public IdentifiableObjectData UpdateItem(IdentifiableObjectData data)
{
data = ProxyClient.Update(data, new ReadOptions());
return data;
}
public IdentifiableObjectData ReadItem(string id)
{
return ProxyClient.Read(id, new ReadOptions());
}
To construct a data object of e.g. a Component you can implement a Component Builder class that implements a create method that does this for you:
public ComponentData Create(string folderUri, string title, string content)
{
var data = new ComponentData()
{
Id = "tcm:0-0-0",
Title = title,
Content = content,
LocationInfo = new LocationInfo()
};
data.LocationInfo.OrganizationalItem = new LinkToOrganizationalItemData
{
IdRef = folderUri
};
using (CoreServiceClient client = provider.GetCoreServiceClient())
{
data = (ComponentData)client.CreateItem(data);
}
return data;
}
Hope this gets you started.

Related

Custom Path to the DisplayTemplates folder [duplicate]

I have the following layout for my mvc project:
/Controllers
/Demo
/Demo/DemoArea1Controller
/Demo/DemoArea2Controller
etc...
/Views
/Demo
/Demo/DemoArea1/Index.aspx
/Demo/DemoArea2/Index.aspx
However, when I have this for DemoArea1Controller:
public class DemoArea1Controller : Controller
{
public ActionResult Index()
{
return View();
}
}
I get the "The view 'index' or its master could not be found" error, with the usual search locations.
How can I specify that controllers in the "Demo" namespace search in the "Demo" view subfolder?
You can easily extend the WebFormViewEngine to specify all the locations you want to look in:
public class CustomViewEngine : WebFormViewEngine
{
public CustomViewEngine()
{
var viewLocations = new[] {
"~/Views/{1}/{0}.aspx",
"~/Views/{1}/{0}.ascx",
"~/Views/Shared/{0}.aspx",
"~/Views/Shared/{0}.ascx",
"~/AnotherPath/Views/{0}.ascx"
// etc
};
this.PartialViewLocationFormats = viewLocations;
this.ViewLocationFormats = viewLocations;
}
}
Make sure you remember to register the view engine by modifying the Application_Start method in your Global.asax.cs
protected void Application_Start()
{
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new CustomViewEngine());
}
Now in MVC 6 you can implement IViewLocationExpander interface without messing around with view engines:
public class MyViewLocationExpander : IViewLocationExpander
{
public void PopulateValues(ViewLocationExpanderContext context) {}
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
return new[]
{
"/AnotherPath/Views/{1}/{0}.cshtml",
"/AnotherPath/Views/Shared/{0}.cshtml"
}; // add `.Union(viewLocations)` to add default locations
}
}
where {0} is target view name, {1} - controller name and {2} - area name.
You can return your own list of locations, merge it with default viewLocations (.Union(viewLocations)) or just change them (viewLocations.Select(path => "/AnotherPath" + path)).
To register your custom view location expander in MVC, add next lines to ConfigureServices method in Startup.cs file:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationExpanders.Add(new MyViewLocationExpander());
});
}
There's actually a lot easier method than hardcoding the paths into your constructor. Below is an example of extending the Razor engine to add new paths. One thing I'm not entirely sure about is whether the paths you add here will be cached:
public class ExtendedRazorViewEngine : RazorViewEngine
{
public void AddViewLocationFormat(string paths)
{
List<string> existingPaths = new List<string>(ViewLocationFormats);
existingPaths.Add(paths);
ViewLocationFormats = existingPaths.ToArray();
}
public void AddPartialViewLocationFormat(string paths)
{
List<string> existingPaths = new List<string>(PartialViewLocationFormats);
existingPaths.Add(paths);
PartialViewLocationFormats = existingPaths.ToArray();
}
}
And your Global.asax.cs
protected void Application_Start()
{
ViewEngines.Engines.Clear();
ExtendedRazorViewEngine engine = new ExtendedRazorViewEngine();
engine.AddViewLocationFormat("~/MyThemes/{1}/{0}.cshtml");
engine.AddViewLocationFormat("~/MyThemes/{1}/{0}.vbhtml");
// Add a shared location too, as the lines above are controller specific
engine.AddPartialViewLocationFormat("~/MyThemes/{0}.cshtml");
engine.AddPartialViewLocationFormat("~/MyThemes/{0}.vbhtml");
ViewEngines.Engines.Add(engine);
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
One thing to note: your custom location will need the ViewStart.cshtml file in its root.
If you want just add new paths, you can add to the default view engines and spare some lines of code:
ViewEngines.Engines.Clear();
var razorEngine = new RazorViewEngine();
razorEngine.MasterLocationFormats = razorEngine.MasterLocationFormats
.Concat(new[] {
"~/custom/path/{0}.cshtml"
}).ToArray();
razorEngine.PartialViewLocationFormats = razorEngine.PartialViewLocationFormats
.Concat(new[] {
"~/custom/path/{1}/{0}.cshtml", // {1} = controller name
"~/custom/path/Shared/{0}.cshtml"
}).ToArray();
ViewEngines.Engines.Add(razorEngine);
The same applies to WebFormEngine
Instead of subclassing the RazorViewEngine, or replacing it outright, you can just alter existing RazorViewEngine's PartialViewLocationFormats property. This code goes in Application_Start:
System.Web.Mvc.RazorViewEngine rve = (RazorViewEngine)ViewEngines.Engines
.Where(e=>e.GetType()==typeof(RazorViewEngine))
.FirstOrDefault();
string[] additionalPartialViewLocations = new[] {
"~/Views/[YourCustomPathHere]"
};
if(rve!=null)
{
rve.PartialViewLocationFormats = rve.PartialViewLocationFormats
.Union( additionalPartialViewLocations )
.ToArray();
}
Last I checked, this requires you to build your own ViewEngine. I don't know if they made it easier in RC1 though.
The basic approach I used before the first RC was, in my own ViewEngine, to split the namespace of the controller and look for folders which matched the parts.
EDIT:
Went back and found the code. Here's the general idea.
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName)
{
string ns = controllerContext.Controller.GetType().Namespace;
string controller = controllerContext.Controller.GetType().Name.Replace("Controller", "");
//try to find the view
string rel = "~/Views/" +
(
ns == baseControllerNamespace ? "" :
ns.Substring(baseControllerNamespace.Length + 1).Replace(".", "/") + "/"
)
+ controller;
string[] pathsToSearch = new string[]{
rel+"/"+viewName+".aspx",
rel+"/"+viewName+".ascx"
};
string viewPath = null;
foreach (var path in pathsToSearch)
{
if (this.VirtualPathProvider.FileExists(path))
{
viewPath = path;
break;
}
}
if (viewPath != null)
{
string masterPath = null;
//try find the master
if (!string.IsNullOrEmpty(masterName))
{
string[] masterPathsToSearch = new string[]{
rel+"/"+masterName+".master",
"~/Views/"+ controller +"/"+ masterName+".master",
"~/Views/Shared/"+ masterName+".master"
};
foreach (var path in masterPathsToSearch)
{
if (this.VirtualPathProvider.FileExists(path))
{
masterPath = path;
break;
}
}
}
if (string.IsNullOrEmpty(masterName) || masterPath != null)
{
return new ViewEngineResult(
this.CreateView(controllerContext, viewPath, masterPath), this);
}
}
//try default implementation
var result = base.FindView(controllerContext, viewName, masterName);
if (result.View == null)
{
//add the location searched
return new ViewEngineResult(pathsToSearch);
}
return result;
}
Try something like this:
private static void RegisterViewEngines(ICollection<IViewEngine> engines)
{
engines.Add(new WebFormViewEngine
{
MasterLocationFormats = new[] {"~/App/Views/Admin/{0}.master"},
PartialViewLocationFormats = new[] {"~/App/Views/Admin//{1}/{0}.ascx"},
ViewLocationFormats = new[] {"~/App/Views/Admin//{1}/{0}.aspx"}
});
}
protected void Application_Start()
{
RegisterViewEngines(ViewEngines.Engines);
}
Note: for ASP.NET MVC 2 they have additional location paths you will need to set for views in 'Areas'.
AreaViewLocationFormats
AreaPartialViewLocationFormats
AreaMasterLocationFormats
Creating a view engine for an Area is described on Phil's blog.
Note: This is for preview release 1 so is subject to change.
Most of the answers here, clear the existing locations by calling ViewEngines.Engines.Clear() and then add them back in again... there is no need to do this.
We can simply add the new locations to the existing ones, as shown below:
// note that the base class is RazorViewEngine, NOT WebFormViewEngine
public class ExpandedViewEngine : RazorViewEngine
{
public ExpandedViewEngine()
{
var customViewSubfolders = new[]
{
// {1} is conroller name, {0} is action name
"~/Areas/AreaName/Views/Subfolder1/{1}/{0}.cshtml",
"~/Areas/AreaName/Views/Subfolder1/Shared/{0}.cshtml"
};
var customPartialViewSubfolders = new[]
{
"~/Areas/MyAreaName/Views/Subfolder1/{1}/Partials/{0}.cshtml",
"~/Areas/MyAreaName/Views/Subfolder1/Shared/Partials/{0}.cshtml"
};
ViewLocationFormats = ViewLocationFormats.Union(customViewSubfolders).ToArray();
PartialViewLocationFormats = PartialViewLocationFormats.Union(customPartialViewSubfolders).ToArray();
// use the following if you want to extend the master locations
// MasterLocationFormats = MasterLocationFormats.Union(new[] { "new master location" }).ToArray();
}
}
Now you can configure your project to use the above RazorViewEngine in Global.asax:
protected void Application_Start()
{
ViewEngines.Engines.Add(new ExpandedViewEngine());
// more configurations
}
See this tutoral for more info.
I did it this way in MVC 5. I didn't want to clear the default locations.
Helper Class:
namespace ConKit.Helpers
{
public static class AppStartHelper
{
public static void AddConKitViewLocations()
{
// get engine
RazorViewEngine engine = ViewEngines.Engines.OfType<RazorViewEngine>().FirstOrDefault();
if (engine == null)
{
return;
}
// extend view locations
engine.ViewLocationFormats =
engine.ViewLocationFormats.Concat(new string[] {
"~/Views/ConKit/{1}/{0}.cshtml",
"~/Views/ConKit/{0}.cshtml"
}).ToArray();
// extend partial view locations
engine.PartialViewLocationFormats =
engine.PartialViewLocationFormats.Concat(new string[] {
"~/Views/ConKit/{0}.cshtml"
}).ToArray();
}
}
}
And then in Application_Start:
// Add ConKit View locations
ConKit.Helpers.AppStartHelper.AddConKitViewLocations();

Will JsonContent get serialised multiple times using Json.NET in Web Api 2

If I have this controller:
public class SomeController : ApiController
{
public SomeInfoDto Get()
{
return new SomeInfoDto();
}
}
When I call /api/Some with a get request I will get JSON in the Content Body because JSON.NET has been kind enough to serialise it for me.
However, if I wanted to send a 500 HTTP code and some JSON I thought I could do this:
public HttpResponseMessage Get()
{
return new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = // not sure what to put here
}
}
So I googled to find out what to put for the Content and found this resource
public class JsonContent : HttpContent
{
private readonly JToken _value;
public JsonContent(JToken value)
{
_value = value;
Headers.ContentType = new MediaTypeHeaderValue("application/json");
}
protected override Task SerializeToStreamAsync(Stream stream,
TransportContext context)
{
var jw = new JsonTextWriter(new StreamWriter(stream))
{
Formatting = Formatting.Indented
};
_value.WriteTo(jw);
jw.Flush();
return Task.FromResult<object>(null);
}
protected override bool TryComputeLength(out long length)
{
length = -1;
return false;
}
}
Which I can easily modify to fit my purposes.
However, my question is, if I get SerializeToStreamAsync to use JsonConvert.SerializeObject(_value) further down the Web Api pipeline will it be serialised again?
I have set the GlobalConfiguration.Configuration like this:
var formatters = GlobalConfiguration.Configuration.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var settings = jsonFormatter.SerializerSettings;
settings.Formatting = Formatting.Indented;
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
My Implementation for the SerializeToStreamAsync is this:
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
using (var streamWriter = new StreamWriter(stream))
{
streamWriter.WriteAsync(JsonConvert.SerializeObject(this.value)).Wait();
streamWriter.FlushAsync().Wait();
}
return Task.FromResult<object>(null);
}
EDIT: Providing a concrete sample with formatter.
If you want to send JSON content with Http Status Code 500, you can use the extension method HttpRequestMessage.CreateResponse. There is no need for any advanced serialization and formatting. More info on that here.
https://msdn.microsoft.com/en-us/library/system.net.http.httprequestmessageextensions.createresponse%28v=vs.118%29.aspx
Request.CreateResponse(HttpStatusCode.InternalServerError, new string[] { "value1", "value2" }, new JsonMediaTypeFormatter())
(Or)
Request.CreateResponse(HttpStatusCode.InternalServerError, new string[] { "value1", "value2" }, 'application/json')

How to test a class with delegate in constructor using Moq

Can someone explain to me how to create an instance of this component in a Moq TestMethod? Here is the definition of the class. I need to test the ProcessAutomaticFillRequest method.
public class AutomaticDispenserComponent : IAutomaticDispenserComponent
{
private readonly Lazy<IMessageQueueComponent> _messageQueueComponent;
protected IMessageQueueComponent MessageQueueComponent { get { return _messageQueueComponent.Value; } }
public AutomaticDispenserComponent(Func<IMessageQueueComponent> messageQueueComponentFactory)
{
_messageQueueComponent = new Lazy<IMessageQueueComponent>(messageQueueComponentFactory);
}
public void ProcessAutomaticFillRequest(FillRequestParamDataContract fillRequestParam)
{
if (fillRequestParam.PrescriptionServiceUniqueId == Guid.Empty)
throw new InvalidOperationException("No prescription service was specified for processing fill request.");
if (fillRequestParam.Dispenser == null)
throw new InvalidOperationException("No dispenser was specified for processing fill request.");
var userContext = GlobalContext.CurrentUserContext;
var channel = string.Format(Channel.FillRequest, userContext.TenantId,
userContext.PharmacyUid, fillRequestParam.Dispenser.DeviceAgentUniqueId);
NotificationServer.Publish(channel, fillRequestParam);
}
Here is how I started my test, but I don't know how to create an instance of the component:
[TestMethod]
[ExpectedException(typeof (InvalidOperationException))]
public void FillRequestFailsWhenPrescriptionServiceUniqueIdIsEmpty()
{
// How do I create an instance of automatiqueDispenserComponent here
// since there is Func as constructor parameter?
var fillRequestParam = new FillRequestParamDataContract
{
PrescriptionServiceUniqueId = Guid.Empty
};
_automaticDispensercomponent.ProcessAutomaticFillRequest(fillRequestParam);
// ...
}
Updated the answer based on the comments below. You need to mock the Func parameter for the test.
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void FillRequestFailsWhenPrescriptionServiceUniqueIdIsEmpty()
{
var mockMsgQueueComponent = new Mock<Func<IMessageQueueComponent>>();
var _automaticDispensercomponent = new AutomaticDispenserComponent
(mockMsgQueueComponent.Object);
var fillRequestParam = new FillRequestParamDataContract
{
PrescriptionServiceUniqueId = Guid.Empty
};
_automaticDispensercomponent.ProcessAutomaticFillRequest(fillRequestParam);
}

How to return an arbitrary json object from Asp.net WebApi RC?

Before I had this code to return an arbitrary json object with just an id property.
How do I convert this to the new RC version of WebApi now that HttpResponseMessage is not supported and it now uses Newtonsofts JSON.NET?
public HttpResponseMessage<JsonValue> Post(MyModel model)
{
var id = _theService.AddEntity(model);
dynamic okResponse = new JsonObject();
okResponse["id"] = id;
return new CreateResponse<JsonValue>(okResponse);
}
And...
public class CreateResponse<T> : ResponseBase<T>
{
public CreateResponse()
: base(HttpStatusCode.Created)
{
}
public CreateResponse(T resource)
: base(resource, HttpStatusCode.Created)
{
}
}
public abstract class ResponseBase<T> : HttpResponseMessage<T>
{
protected ResponseBase(HttpStatusCode httpStatusCode)
: base(httpStatusCode)
{
}
protected ResponseBase(T resource, HttpStatusCode httpStatusCode)
: base(resource, httpStatusCode)
{
if (resource is IApiResource)
{
var apiResource = resource as IApiResource;
var resourceLocation = new ResourceLocation();
apiResource.SetLocation(resourceLocation);
Headers.Location = resourceLocation.Location;
}
}
}
The CreateResponse extention method does not accept dynamic variables.
Please change
dynamic okResponse = new JsonObject();
to something like
var okResponse = new JsonObject();
Please see this link also:
https://aspnetwebstack.codeplex.com/discussions/359242
Use Request.CreateResponse(statuscode, content) inside your controller
Maybe I'm missing something in your question, but you could just do this:
public dynamic Post(MyModel model)
{
var id = _theService.AddEntity(model);
return new { id = id };
}
EDIT: assuming your client sets the Content-type to application/json

TDD problem in ASP.NET MVC3 (with DI)

I am attempting to write some Tests for a small project of mine but they seem to fail (I am starting with 1 test 'Create_Class')
I use the repository pattern and use Constructor Dependency Injection:
public KlasController() {
db = ObjectContextPerHttpRequest.Context;
KlasRepo = new KlasRepository(db);
LesRepo = new LesRepository(db);
OpdrachtRepo = new OpdrachtRepository(db);
}
//dependency injection constructor
public KlasController(IKlasRepository KlasRepo, ILesRepository LesRepo,
IOpdrachtRepository OpdrachtRepo) {
this.KlasRepo = KlasRepo;
this.LesRepo = LesRepo;
this.OpdrachtRepo = OpdrachtRepo;
}
here is my TestClass with testinitializer (which runs before every test) and the first test
[TestClass()]
public class KlasControllerTest
{
private KlasController Controller;
private IOpdrachtRepository OpdrachtRepo;
//Use TestInitialize to run code before running each test
[TestInitialize()]
public void MyTestInitialize()
{
OpdrachtRepo = new DummyOpdrachtRepository();
Controller = new KlasController(new DummyKlasRepository(),
new DummyLesRepository(), OpdrachtRepo);
Opdracht TestOpdracht = new Opdracht
{
OpdrachtID = 1,
VakID = 1,
StamNummer = "im1"
};
Vak TestVak = new Vak { VakID = 1, VakNaam = "FOOP" };
TestOpdracht.Vak = TestVak;
OpdrachtRepo.addOpdracht(TestOpdracht);
}
/// <summary>
///A test for Index
///</summary>
[TestMethod()]
public void CreateKlasDirectsToToonKlassen()
{
Klas Klas = new Klas { KlasNaam = "2dNet" };
RedirectToRouteResult view = Controller.Create(1) as RedirectToRouteResult;
Assert.IsNotNull(view);
Assert.AreEqual("ToonKlassen", view.RouteValues["action"]);
}
}
at the moment I get a nullreferenceException on the view (assert.isNotNull fails)
and here is one of my DummyRepository's:
class DummyOpdrachtRepository : IOpdrachtRepository
{
List<Opdracht> opdrachten;
public DummyOpdrachtRepository()
{
opdrachten = new List<Opdracht>();
}
public void addOpdracht(Opdracht opdracht)
{
opdrachten.Add(opdracht);
}
public string GetDocentID(int OpdrachtID)
{
var opdracht = opdrachten.Where(o => o.OpdrachtID == OpdrachtID).FirstOrDefault();
return opdracht.StamNummer;
}
public Opdracht Find(int id)
{
return opdrachten.Where(o => o.OpdrachtID == id).FirstOrDefault();
}
}
Normally I should have written the tests Before writting the code, I know (and I am convinced off TDD, as I have used it successfully in my latest Java-project). but it just doesn't seem to work..
here is the code for KlasController.Create action
public ActionResult Create(int id) //id = opdrachtID
{
var Opdracht = OpdrachtRepo.Find(id);
Vak vak;
if(Opdracht != null)
vak = Opdracht.Vak;
else
throw new NullReferenceException("Deze opdracht werd niet gevonden");
return View(new CreateKlasModel(id,vak));
}
I know this is a lot of code, but I really want to make this work.
Thanks for helping me out in advance :)
As vladimir77 already says in his comment, the method public ActionResult Create(int id) is of type ViewResult, so either you change you method to do areturn RedirectToRoute() or you change your test to
ViewResult view = Controller.Create(1);
Assert.IsNotNull(view);
A ViewResult can not be cast as a RedirectToRouteResult.

Resources