Event not working - tridion

I am new to Tridion Event System. I have written a small code.
[TcmExtension("MyEventHandlerExtension")]
public class EH : TcmExtension
{
public EH()
{
Subscribe();
}
public void Subscribe()
{
//EventSystem.Subscribe<Component, DeleteEventArgs>(HandlerForInitiated, EventPhases.Initiated);
EventSystem.Subscribe<Tridion.ContentManager.CommunicationManagement.Page, Tridion.ContentManager.Extensibility.Events.PublishOrUnPublishEventArgs>(HandlerForCommitted, EventPhases.All);
}
private void HandlerForCommitted(IdentifiableObject subject, PublishOrUnPublishEventArgs args, EventPhases phase)
{
TDSE obj = new TDSE();
Tridion.ContentManager.Interop.TDS.Publication pub = obj.GetPublication("tcm:0-150-1");
Tridion.ContentManager.Interop.TDS.Page pubPage = obj.GetPage("tcm:150-12374-64", pub);
pubPage.Publish("tcm:0-1-65538", false, true, false, default(DateTime), default(DateTime), default(DateTime));
}
}
using this code i wanted to publish a page everytime when a publish and unpublish event occur.
I build this code and register its path in tridion config file .
But its not working.Please Help

Ok, first of all remove all your TDSE code, you should use TOM.NET. You can get session as subject.Session
Then make sure you have registered this extension in Tridion.ContentManager.config and restarted your system
And finally - if something doesn't work, just add simple code that will create a file in your HandlerForCommitted whenever event occurs, this way you will be able to see if your extension get executed.

The 2011 Event System uses the TOM.NET API and not the TOM API. Please do not create new TDSE objects in the 2011 Event System. Even though you can reference the old Interop libraries, there is no reason to do so with 2011. Using the TOM.NET libraries you should see better performance and also the code is future-proof.
Mihai Cadariu has a nice example where he uses TOM.NET to Publish a page from a Tridion Template. Adjusting the code to check for previewmode or publish mode and setting your own user and priority (instead of reading it from the current transaction) should work well.
Below code from http://yatb.mitza.net/2012/05/publishing-from-template-code-using.html
public void Publish(Engine engine, String tcmUri, User user, PublishPriority priority)
{
Session session = new Session(user.Title);
PublishInstruction publishInstruction = new PublishInstruction(session);
RenderInstruction renderInstruction = new RenderInstruction(session);
renderInstruction.RenderMode = RenderMode.Publish; // work around. needs to be specified for binaries.
publishInstruction.RenderInstruction = renderInstruction;
List<IdentifiableObject> items = new List<IdentifiableObject>() { session.GetObject(tcmUri) };
List<PublicationTarget> targets = new List<PublicationTarget>() { engine.PublishingContext.PublicationTarget };
PublishEngine.Publish(items, publishInstruction, targets, priority);
session.Dispose();
}
// called with
PublishTransaction currentTransaction = TemplateUtils.GetPublishTransaction(engine);
TemplateUtils.Publish(engine, itemUri, currentTransaction.Creator, currentTransaction.Priority);

Your code seems to have the three things I "normally" forget:
the class is public
it extends TcmExtension
it has a TcmExtension attribute
If you've registered the class correctly in the configuration file, it should just be a matter of restarting the relevant module(s). In this case I'd expect those to be the Publisher and TcmServiceHost services.
After restarting those modules and triggering a publish action, you should see an event being logged (in the Windows event viewer) that your extension is being loaded.
If that even shows, it means your assembly is being loaded into the relevant Tridion process and the class is being recognized and instantiated.
If at this stage your handler doesn't fire you may have to consider listening to a different event. Whenever I want to interact with the publishing, I end up listening for the SaveEventArgs of a PublishTransaction, instead of the PublishOrUnPublishEventArgs on the Page.

Related

PRISM Modular dependencies

I have a question regarding module dependencies to other module. I have researched regarding about how different modules communicate with each other but I am not sure what to use and I quite need some clarifications how am I going to use them properly.
How do I load modules depending with each other? e.g. Module A needs to navigate to Module B one of the views of it. Should I load Module A first and then load Module B when I need to navigate to it?
How do I set dependencies with each module? Should I configure them inside the ModuleCatalog resulting into moduleCatalog.AddModule<ModuleB>("ModuleB", InitializationMode.OnDemand, "ModuleA"); or should I do: [ModuleDependency(ModuleA)] on top of the Module B class
Module A needs to navigate to one of the pages in Module B and I have to pass navigation parameters into Module B. Should I use a shared service or an event aggregator ? though as much as possible I want to lessen the use of an event aggregator
This is the beauty of Prism in my opinion.
You have a lot of flexibility when it comes to where to load the modules.
In the past, I have used the IModuleManager which I can inject into a ViewModel of any module and from there I can call the Load Method.
The load method takes in the string name of the module that you have registered.
When registering I have also set the Load Type to onDemand so the module is only loaded only when I specifically call the load method.
So in your scenario, you could load Module B whenever you need to in Module A.
It could be triggered by some business logic for your application.
To answer your second question you can then simply just pass your parameters using the navigation parameters functionality of the Navigation service
var param = new NavigationParameters();
param.Add("trip", someObject);
await NavigationService.NavigateAsync("TripDetailsPage", param);
EDIT:
So if you want to know whether a Module has been loaded or not you could do something like the following:
public class ModuleService : IModuleService
{
private readonly IModuleCatalog _moduleCatalog;
private readonly IModuleManager _moduleManager;
public ModuleService(IModuleCatalog moduleCatalog, IModuleManager moduleManager)
{
_moduleCatalog = moduleCatalog;
_moduleManager = moduleManager;
}
public bool Exists(string moduleName)
{
return _moduleCatalog.Modules.Any(x => x.ModuleName == moduleName);
}
public bool Initialized(string moduleName)
{
return _moduleCatalog.Modules.Any(x => x.ModuleName == moduleName && x.State == ModuleState.Initialized);
}
public void LoadModule(string moduleName)
{
_moduleManager.LoadModule(moduleName);
}
}
So by combining the functionality of the ModuleManager and the Module Catalog, I can check if a module is already loaded using the modules ModuleState property

Upgrading Unity container breaks interception mechanism

We recently upgraded Microsoft's Unity in our project from version 3.5.1404 to 5.8.6. With only a few minor adjustments in our code this upgrade seemed to go pretty easy. It resolves all our registered instances without a problem. However, we also use Unity's Interception-mechanism to cache some results that a method returns in AOP-style. This cache mechanism is broken since the upgrade and we can't figure out why. Apparently, our attributes are no longer called when a decorated method is called.
It currently works as follows. We register the interception like this:
var container = new UnityContainer();
container.RegisterType<IService, Service>(some_lifetime);
container.AddNewExtension<Interception>();
container.Configure<Interception>()
.SetInterceptorFor(typeof(IService), new InterfaceInterceptor());
In the Service class, which implements IService we have a method that is decorated with a custom Cache attribute, like this:
public class Service : IService {
[Cache(..)]
public Result SomeMethod() {
// Some code
}
}
And lastly, our custom Cache attribute which inherits from Unity's HandlerAttribute:
public class CacheAttribute : HandlerAttribute
{
// ctor
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new CacheCallHandler(container, and, some, more);
}
}
When method SomeMethod used to be called with version 3.5.1404 the attribute was called first, but since 5.8.6 it no longer calls this attribute. The code however, does compile. The changes we had to make to make it compile are mostly changes in usings. Like Microsoft.Practices.Unity.InterceptionExtension which changed to Unity.Interception.PolicyInjection.Policies.
We can't figure out why this mechanism is no longer working. And even after extensive research on the internet, we can't find a way to get this to work. Any suggesties would therefore be greatly appreciated!
I got in your exact same situation while trying to refresh some legacy code. I got it working with:
Changing:
config.SetInterceptorFor(myType, new InterfaceInterceptor()); for
config.SetInterceptorFor(myType, new TransparentProxyInterceptor());
Registering the class that inherits from HandlerAttribute
Container.RegisterType<MyHandlerAttribute>(new PerRequestLifeTimeManager());
Register each type to intercept with special InjectionMembers:
Container.RegisterType<MyClassToBeIntercepted>(
new Interceptor<TransparentProxyInterceptor>(),
new InterceptionBehavior<PolicyInjectionBehavior>()
);

How to determine in a Custom Resolver if I am publishing or unpublishing? Tridion 2009 SP1

I'm trying to capture when a component is unpublished. I try some approaches but I don't have the result that I want. My attempts are:
In Event System. But this not works because there are a known bug in Windows about MSXML and COM+.
I try to build my own IResolver but there I cannot determine if it's a publishing or unpublishing action.
I try to build my own ITransportPackageHandler. There, I have a function called HandleResolvedItemForUnPublishing but I don't have any information about PublicationTarget and I don't know if it's unpublished from staging or live.
Can someone help me? I think that I can solve the problem if:
At the IResolver I can determine if the component is unpublishing.
At the ITransportPackageHandler I can access to the PublicationTarget info
If I can pass info from IResolver to the ITransportPackageHandler in a context variable or something similar.
thank you very much.
Gustavo.
You should be able to look at the ResolvePurpose of the ResolveInstruction that you get as one of the parameters in the custom resolver. Something along these lines:
public void Resolve(IdentifiableObject item, ResolveInstruction instruction, PublishContext context, ISet<ResolvedItem> resolvedItems)
{
if (instruction.Purpose == ResolvePurpose.Publish || instruction.Purpose == ResolvePurpose.RePublish)
{
// We are publishing
}
else if(instruction.Purpose == ResolvePurpose.UnPublish)
{
// We are unpublishing
}
// Don't know if this one exists in 2009, it exists in 2011 SP1
else if(instruction.Purpose == ResolvePurpose.UnknownByClient)
{
// The server is doing something that I don't understand (yet?)
}
}
EDIT
I refused to not find a way to make this work...
Indeed, in Tridion 2009 you don't have a Purpose on the resolve instruction. You do have an Action in the Publish Transaction, but this one is not exposed directly in the resolver. Here's how I found out if I'm publishing or unpublishing - your call if think it's overkill, but performance on my non-production VM was pretty good.
Find the current item we're resolving for
Load the list of PublishTransaction with a state of "In Progress"
Find the transaction for the current item
Determine the action by looking at the Action attribute
Filter filter = new Filter();
filter.Conditions["InfoType"] = 2; // Get transactions in Progress
foreach (XmlNode node in item.Session.GetList(typeof(PublishTransaction), filter))
{
if(node.Attributes["ItemID"].Value.Equals(item.Id.ToString()))
{
// we have a winner
string action;
if (node.Attributes["Action"].Value.Equals("0"))
action = "Publish";
if (node.Attributes["Action"].Value.Equals("1"))
action = "Unpublish";
}
}
Assuming you use 2011 you can bind an event handler to the Publish Transaction Save event and verify the State. Then, when the Component is unpublished you can perform the logic you needed.
public sealed class PublishedToEventHandler: TcmExtension
{
public PublishedToEventHandler()
{
EventSystem.SubscribeAsync<PublishTransaction, SaveEventArgs>(
(subject, args, phase) =>
{
if (!PublishStransactionStateIsSuccessfullyCompleted(subject))
return;
},
EventPhases.TransactionCommitted
);
}
static bool PublishStransactionStateIsSuccessfullyCompleted(PublishTransaction transaction)
{
return transaction.State == PublishTransactionState.Success ||
transaction.State == PublishTransactionState.Warning;
}
}
Before anything is handled in this event you can verify the Instruction.ResolveInstruction.Purpose property of the transaction to see whether or not you are publishing on unpublishing.
The transaction has a ProcessedItems collection, and each contains the Page or Component in the ResolvedItem.Item propery of the ProcessedItem object. When its a Page you do need to obtain the Components embedded on the Page to do anything with them.
Let me know if you have any more questions.

Notifying that all properties have changed on a ViewModel

I am working on a Silverlight application using V3 SP1 of MVVM Light Toolkit.
My application is fully French/English. All UI elements (buttons, labels, etc.) and all the data (models). I need dynamic language switching and this is fully implemented and works with anything coming from a resource file. What I am struggling with is the ViewModels.
The Models have language specific prperties (DescriptionEn, DescriptionFr) and an additional property call LocalizedDescription which uses the current culture to return call the language specific property.
When the language changes (via a button click) I raise and broadcast (via the Messenger) a property changed event.
In each of my ViewModels, I register to receive the property changed message for the language swap.
I want to notify all the properties of the ViewModel that something has changed.
From: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.propertychanged.aspx
The PropertyChanged event can indicate all properties on the object have changed by using either null or String.Empty as the property name in the PropertyChangedEventArgs.
However, since the toolkit abstracts the raising of the changed event with RaisePropertyChanged(...) I cannot get this to work. I have also examined the source of the tookit and discovered that RaisePropertyChanged calls VerifyPropertyName(..) which in turn returns an error is the property does not belong to the ViewModel. I also noticed that the VerifyPropertyName method is attributed with Conditional("DEBUG"), but even if I choose the Release configuration, the ArgumentException("Property not found") is still raised.
Does anyone know of a way to get this to work using the toolkit aside from manually calling RaisePropertyChanged for every property of the ViewModel?
Follow-up:
Based on the comment from Simon, I attempted to create my own class that extends ViewModelBase. I looked at the source on CodePlex and decided to create a single method called RaiseAllPropertyChanged(). It would simply be a copy of the RaisePropertyChanged(string propertyName) but without the parameter and without the call to VerifyPropertyName(...). I cannot get it to work. Here is what I have.
public class ViewModelBaseExtended : ViewModelBase
{
protected void RaiseAllPropertyChanged()
{
var handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(String.Empty));
}
}
}
But I get a compiler error: The event 'GalaSoft.MvvmLight.ViewModelBase.PropertyChanged' can only appear on the left hand side of += or -=. This is a copy of the code that is used in the ViewModelBase.
Can someone offer some advice as to how to get this to work?
Solution:
I copied all the code from ViewModelBase into a new class. I then added the method RaisePropertyChanged() mentioned above which instantiates the PropertyChangedEventArgs class with String.Empty. This is now the new subclass for my ViewModels.
Thanks again to Simon for leading the way!
In case you're reading this in 2016, you can use ObservableObject and notify that all of the properties have changed by doing:
RaisePropertyChanged(string.Empty);
Unfortunately this is not possible with the current code-base of MVVMLight
In the short term your have 2 options:
User your own custom base class. And by custom base class I mean "Do not inherit from the MVVMLight class".
Download and compile MVVMLight in Release mode. This will force the "VerifyPropertyName" method to be excluded. Of course then you don't get the value of property name checks.
I am sure Laurent Bugnion will have this fixed soon.
A lighter solution to this problem would have been to override RaisePropertyChanged(string propertyName) in your class :
protected override void RaisePropertyChanged(string propertyName)
{
if (propertyName != null)
{
base.RaisePropertyChanged(propertyName);
}
else
{
var handler = PropertyChangedHandler;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(null));
}
}
}

Static variables and long running thread on IIS 7.5

Help me solve next problem.
I have ASP .NET MVC2 application. I run it on IIS 7.5. In one page user clicks button and handler for this button sends request to server (jquery.ajax). At server action in controller starts new thread (it makes long time import):
var thread = new Thread(RefreshCitiesInDatabase);
thread.Start();
State of import is available in static variable. New thread changes value of variable in the begin of work.
User can check state of import too with the help of this variable, which is used in view. And user sees import's state.
When I start this function few minutes everything is okey. On page I see right state of import, quantity of imported records is changed, I see changes in logs. But after few minutes begin troubles.
When I refresh page with import state sometimes I see that import is okey but sometimes I see page with default values about import (like application is just started), but after that again I can see page with normal import's state.
I tried to attach Visual Studio to IIS process and debug application. But when request comes to controller sometimes static variables have right values and sometimes they have default values (static int has 0, static string has "" etc.).
Tell me what I do wrong. May be I must start additional thread in other way?
Thanks in advance,
Dmitry
I add parts of code:
Controller:
public class ImportCitiesController : Controller
{
[Dependency]
public SaveCities SaveCities { get; set; }
//Start import
public JsonResult StartCitiesImport()
{
//Methos in core dll, which makes import
SaveCities.StartCitiesSaving();
return Json("ok");
}
//Get Information about import
public ActionResult GetImportState()
{
var model = new ImportCityStatusModel
{ NowImportProcessing = SaveCities.CitiesSaving };
return View(model);
}
}
Class in Core:
public class SaveCities
{
// Property equals true, when program are saving to database
public static bool CitiesSaving = false;
public void StartCitiesSaving()
{
var thread = new Thread(RefreshCitiesInDatabase);
thread.Start();
}
private static void RefreshCitiesInDatabase()
{
CitiesSaving = true;
//Processing......
CitiesSaving = false;
}
}
UPDATE
I think, I found problem, but still I don't know how solve it. My IIS uses application pool with parameter "Maximum Worker Processes" = 10. And all tasks in application are handled by few processes. And my request to controll about import's state always is handled by different processes. And they have different static variables. I guess it is right way for solving.
But I don't know how merge all static values in one place.
Without looking at the code, here are the obvious question. Are you sure your access is thread safe (that is do you properly use lock to update you value or even access it => C# thread safety with get/set) ?
A code sample could be nice.
thanks for the code, it seem that CitiesSaving is not locked properly before read/write you should hide the instance variable behind a property to handle all the locking. Marking this field as volatile could also help (see http://msdn.microsoft.com/en-us/library/aa645755(v=vs.71).aspx )

Resources