Starting custom Sharepoint timer programatically II
A few days ago I wrote about How to start custom SharePoint timer programatically. In this post, I talked about the problems that we could find before starting a Sharepoint timer programatically.
Today, I want to expand on this topic with another post. First, I want to talk about instruccions that we need for starting the timer.
Below, there is a piece of code to start the timer programatically.
public staticvoid StartJob(thisSPSite Site, string JobName, Dictionary<string, object> properties)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite elevatedSite = newSPSite(Site.ID))
{
SPSite site = elevatedSite;
SPJobDefinition myjob = FindJob(elevatedSite,JobName);
foreach(string k in properties.Keys)
{
myjob.Properties[k] = properties[k];
}
myjob.RunNow();
}
});
}
It’s nothing special. Maybe the way that we can find the timer job instance is a bit important to know how to avoid problems.
public staticSPJobDefinition FindJob(thisSPSite elevatedSite, string JobName)
{
SPJobDefinition myjob = null;
foreach (SPJobDefinition job in elevatedSite.WebApplication.JobDefinitions)
{
if (job.Name.Equals(JobName, StringComparison.OrdinalIgnoreCase))
{
myjob = job;
break;
}
}
return myjob;
}
In timer job, also, there is a way to bypass parameters by properties. This properties could be persistent or not, it depends on how you declare it in timer job.
It’s very common that a timer job is instantiate in site level and we need to execute to web level. This kind of problem can be resolved using properties. You can see an example on this lines.
Dictionary<string, object> properties = newDictionary<string, object>();
properties.Add(“isManual”, true);
properties.Add(“force-web-id”, SPContext.Current.Web.ID);
SPContext.Current.Web.Site.StartJob(JobDefinition.Name, properties);
And what about its status? Reading the status of timer job could be a little complicated. You need to reiterate the status list and get the last log written by the job. For example if job is running:
public static bool IsJobRunning(thisSPSite Site, string JobName)
{
bool isrunning = false;
InformationJob ijob = newInformationJob();
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite elevatedSite = newSPSite(Site.ID))
{
SPJobDefinition myjob = FindJob(elevatedSite,JobName);
if (myjob.IsDisabled)
{
isrunning = false;
}
else
{
try
{
var e = myjob.HistoryEntries.OrderByDescending(i => i.StartTime).First();
isrunning = e.Status ==SPRunningJobStatus.Initialized;
}
catch
{
isrunning =false;
}
}
}
});
return isrunning;
}
I recommend creating another list to register your own log and to set one mark for knowing when it begins and another for knowing when it finishes. Here you can see an example of the list:
So, in this way, you only need to read your own log and find the mark that tells you what the status of your job is. For example if job is finished:
private bool IsJobFinished()
{
bool isFinished = false;
InformationJob ijob = newInformationJob();
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite elevatedSite = newSPSite(SPContext.Current.Site.ID))
{
SPJobDefinition myjob = FindJob(elevatedSite);
if (myjob.IsDisabled)
{
isFinished =false;
}
else
{
try
{
SPList listLog = SPContext.Current.Web.GetListByUrl(JobDefinition.LogListUrl);
if (listLog.Items.Count == 0)
{
isFinished =true;
}
else
{
var joblog = listLog.Items.OfType<SPListItem>().Where(i =>
i["TypeMessage"].ToString() == TypeMessageLogJobs.End.ToString() &&
((DateTime)i["Timestamp"]).CompareTo(listLog.Items.OfType<SPListItem>().Max(ii => (DateTime)ii["Timestamp"])) == 0 ).First();
isFinished =true;
}
}
catch
{
isFinished =false;
}
}
}
});
return isFinished;
}
Navegación a paginas XAML de otros ensamblados
Tanto en WPF como en Silverlight como en Windows Phone trabajamos con ventanas escritas en XAML que son XML que definen la interface de usuario.
Puede ser muy habitual tener definidas estas ventanas en otros ensamblados, como por ejemplo librerías, y en el momento de querer navegar hasta esta ventana tenemos la duda de como se puede hacer ya que el servicio de navegación en WPF funciona con Uri.
Así que, cual es la Uri de una ventana definida en otro ensamblado?
/{assemblyName};component/{pathToResource}
Como por ejemplo : “/SharedPages;component/TestPage.xaml” donde SharedPages es el nombre del ensamblado y /TestPage.xaml la ruta a partir de la raíz del proyecto para encontrar la ventana.
Canviar la pàgina d’inici en Windows Phone
Amb un dels projectes que estic treballo amb Windows Phone, concretament amb Windows Phone 8. M’he trobat amb la necessitat de modificar la pàgina d’inici de l’aplicació. Pensant que era com les aplicacions WPF de escriptori entro a les propietats del projecte i em fixo amb la propietat “Objeto de inicio” i veig qu correctament està posat en App. Així que miro dins la classe App de la meva aplicació tot buscant alguna instrucció que redirigeixi la RootFrame a MainPage.xaml, però tampoc.
És llavors quan em decideixo a buscar per internet com es fa i em trobo amb pàgines que parlen de Windows Phone 7 amb el Visual Studio 2010 em donen la clau de que s’ha de modificar el fitxer WMAppManifest.xml que es troba dins la carpeta Properties del projecte.
Setting start page of Windows Phone dynamically through code
Així que jo, amb el Visual Studio 2012 obro el fitxer i em trobo amb la pantalla següent
Efectivament veig el camp que indica la pàgina inicial i la trec, però el Visual Studio 2012 m’avisa amb error de que és obligatori al guardar.
Miro el seu codi XML i veig que s’ha guardat en blanc tal i com vull.
Compilo tot correcte i funciona.
Així que fet, per canviar la pàgina inicial de una aplicació Windows Phone s’indica des de WMAppManifest.xml
Starting custom Sharepoint timer programatically
When you need to start a timer job in SharePoint you can do it from Central Administration with a cool web interface.
There, you can see all timers Jobs in your farm and control their status and logs. But, sometimes we need to start a timer job from a Sharepoint front-end interface. I mean, a simple user wants to start a process that runs in background.
Yes, we have a timer job as a class, you can instantiate and call its RunNow method for starting the process. But, we need to do something else before that.
For security reasons, users can’t start timer jobs in front-end interface. In fact, you must write this Power Shell sentence in the application server or write in your feature activation method in feature receiver class.
PowerShell script
$snap = Get-PSSnapin | Where-Object { $_.Name -eq “Microsoft.SharePoint.Powershell” }
if ($snap -eq $null)
{
Add-PSSnapin “Microsoft.SharePoint.Powershell”
}
# get content web service
$contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
# turn off remote administration security
$contentService.RemoteAdministratorAccessDenied = $false
# update the web service
$contentService.Update()
C# code
// SET THE REMOTE ADMINISTATOR ACCESS DENIED FALSE
SPWebService.ContentService.RemoteAdministratorAccessDenied = false;
SPWebService.ContentService.Update();
Remeber that any timer job in Sharepoint is started by SP Timer and you need to restart that service in all farm servers when any change in your custom job are made.
Without modifing RemoteAdministrationAccessDenied to false when you try to start a job programatically a Access denied exception is thrown.
More information:
Custom SPJobDefinition and “Access denied” Error
Custom job and System.Security.SecurityException: Access Denied
Ejecución de una página ASP.NET
Parte fundamental para entender como funciona ASP.NET y como puede afectar esto a tu forma de programar tus aplicaciones web. ASP.NET se planteó que la programación fuera “Event driven” que significa que cada página genera eventos. Entender cual es el orden de generación de los eventos es esencial para programar correctamente. Para verlo hablamos del ciclo de vida de la página.
Cuando llega una petición :
Construir el árbol de controles
Verás que las páginas en ASP.NET utilizan controles de servidor y esos controles están ordenados en forma de árbol tal y como ya pasa en las aplicaciones Winforms.
Evento Init
El primer evento que se ejecuta en una página es el Init. Tienes creados los controles pero estos aún no tienen los valores.
Cargar el estado y los datos recibidos
Aquí es donde se guardan los datos en los controles. En el caso que la petición sea un submit de un formulario previamente enviado también se guardaran estos valores nuevos.
Evento Load
El evento más comúnmente utilizado. Es donde tienes acceso a los valores en los controles. Aquí es importante no hacer inicializaciones sin antes comprobar que no se está realizando una petición Postback. Postback es la forma que tenemos para llamar las peticiones que envían información al servidor. Es decir, las llamadas creadas mediante una acción del usuario. No son Postback cuando la petición es directa mediante la barra de navegación del explorador o mediante un link simple (etiqueta a) de la página.
Evento acción del usuario / evento cambios en controles
Si se trata de una petición Postback quiere decir que el usuario ha realizado una acción, como por ejemplo el clic de un botón, esta acción es un evento que se debe tratar. También pueden ocurrir otros eventos que no tienen por que ser acciones de botones. Pueden ser eventos producidos por el cambio en una lista, el cambio en un texto. Este tipo de eventos también se tratan.
Evento LoadComplete
El evento anterior a procesar la página para su entrega al cliente.
Guardar el estado
Una de las características del ASP.NET es la utilización en cada página de una variable de estado denominada ViewState que permite recuperar el estado en que se ha enviado inicialmente la página. Fíjate que sin el ViewState no podrías saber que eventos de modificación se han producido.
Renderizar los controles
Otra característica de ASP.NET es la utilización de controles de servidor. Estos controles se caracterizan por empezar en “asp:”, tener un ID y un runat=”server”. Estos controles no pueden ser interpretados por ningún navegador ya que ellos solo interpretan Html. Por eso antes de enviar necesitas transformar los controles de servidor en Html.
Evento Unload
Ultimo evento en el ciclo. Se pueden liberar recursos ocupados en el proceso.
Para más información puedes comprar mi libro Guia Práctica de Asp.net
Más información:
Información general sobre el ciclo de vida de una página ASP.NET
Aspnetdb a Windows Azure
El meu ultim post ja et parlava de que últimament estic treballant amb Windows Azure. Avui aprofito per explicar com ho podem fer per implementar ASP.NET Membership a Windows Azure.
Com ja segurament saps una de les coses que necessitem és les taules de la base de dades aspnetdb a la base de dades que hem creat Azure.
Una de les maneres més senzilles és descarregar-te els scripts des de la web de Microsoft que et poso a sota d’aquestes linies i amb el SQL Server Managment Studio executarlos per tal de que s’ens creein les taules dins d’una base de dades existent o una de nova.
http://archive.msdn.microsoft.com/KB2006191/Release/ProjectReleases.aspx?ReleaseId=3539
Després d’això ja podem publicar la web o el servei web assegurant que les cadenes de conexió estan ben definides en el web.config
Tens més informació aqui:
Deploying your Database to SQL Azure (and using ASP.Net Membership with it)
Step-by-step: Migrating ASP.NET Application to Windows Azure (Part 2–Preparing SQL Azure Database)







