mercoledì 24 settembre 2008

Creare un servizio Windows con C#

Un Windows Service (in italiano detto anche Servizio) è un'applicazione che gira in background all'interno di Windows. L'applicazione viene poi gestita da uno snap-in disponibile nel MMC di gestione del sistema sotto "Services and Applications/Service" il quale permette di impostare la modalità con cui il servizio parte, l'account con cui questo programma gira (LOCAL SERVICE o NETWORK SERVICE ad esempio), i parametri che possono essere passati in fase di lancio, le operazioni da compiere nel caso in cui il lancio del programma non vada a buon fine, ecc.
L'applicazione da trasformare in servizio, si occupa di controllare una casella email per la ricezione di richieste d'intervento che vengono poi filtrate in base al mittente ed inserite nel database del sistema gestionale per poi essere visualizzate poi tramite interfaccia web.Inizialmente l'applicazione veniva avviata automaticamente al login di un utente ed eseguita in background. Naturale evoluzione e' quindi quella di trasformarla in servizio in modo che possa venir avviata anche senza effettuare il login di un utente.
Per fare cio, occorre selezionare il template "Windows Service"

public partial class service1 : ServiceBase
{
public service1()
{
// Costruttore.
}
protected override void OnStart(string[] args)
{
// Codice eseguito all'avvio del servizio.
}
protected override void OnStop()
{
// Codice eseguito al termine del servizio.
}
}

Il metodo OnStart verra' chiamato ogni volta che il servizio verra' avviato (Manualmente o Automaticamente a seconda di come e' stato impostato), tramite il parametro args recuperiamo i parametri che decidiamo di passargli al momento dell'avvio (Nella finestra di configurazione dei servizi e' possibile impostare i parametri di avvio). Ad esempio nel metodo OnStart possiamo attivare un Timer per l'esecuzione del nostro codice.
Ora dobbiamo aggiungere l'installer che si occupa di installare l'applicazione come servizio. Per fare cio' dobbiamo andare in modalita' Design sulla classe che contiene il servizio, nel nostro caso service1, tasto destro e poi Add Installer
Tramite l'installer possiamo definire nelle sue proprieta' le credenziali con cui dovra' partire il servizio: in particolar modo il tipo di account (LocalSystem)
Possiamo ora aggiungere un progetto per il setup alla nostra soluzione. Andiamo quindi su File -> Add -> New Project... e selezioniamo "Setup and Deployment" -> "Setup Project" Ora dobbiamo specificare quali file devono essere aggiunti al setup e dove andranno messi (di default) sul computer dove girera' la nostra applicazione. Clichiamo con il tasto destro su Application Folder e poi selezioniamo Add -> Project Output...:
Da questa finestra selezioniamo l'output del nostro progetto, in questo modo quando effettueremo il build della soluzione, l'eseguibile della nostra applicazione verra' inserito all'interno del setup.
Ora associamo il progetto di setup al progetto della nostra applicazione. Per fare questo dobbiamo cliccare su Setup nella finestra Solution Explorer: sulla barra di tale finestra compariranno delle nuove icone, clicchiamo su Custom Actions Editor.
Aperta la finestra di dialogo relativa a Custom Actions Editor dobbiamo cliccare su Application Folder e successivamente selezionare Primary output from [Your service] (Active)Fatto questo siamo pronti per compilare ed installare il servizio.

mercoledì 3 settembre 2008

Caricare un'immagine e modificarla

Se vogliamo visualizzare un'immagine, e rivisualizzarla in seguito ad una modifica dobbiamo stare attenti alla cache che si ricorda la vecchia immagine e non tiene conto della modifica.
Un metodo potrebbe essere quello di caricare l'immagine e postporre un parametro casuale, in modo da far ricaricare ogni volta l'immagine.
Ad esempio:


Image1.ImageUrl = "~/img/immagine.jpg?t=" + DateTime.Now.Ticks.ToString

in Questo modo l'immagine viene ricaricata ogni volta... comprese le modifiche ;)

Il DefaultButton, una questione importante

Scrivendo la mia applicazione ho trovato non pochi problemi con il bottone di default.
Infatti se non viene impostato per default al click dell'invio viene attivato il primo bottone trovato nella pagina.
Il metodo che ho utilizzato per ovviare a questo problema è questo:

inserire dei Panel, e nella dichiarazione utilizzare il

defaultbutton="idButtonDesiderato"

in questo modo gestisco in maniera granulare il bottone di default.

martedì 26 agosto 2008

WebPart e IIS

Per il corretto funzionamento delle WebPart, l’applicazione deve essere impostata con
authentication mode="Forms"
In questo modo, sulla prima pagina del sito dobbiamo gestire l’utente da caricare nei cookie.
Ad Esempio

Dim userData As String = "ApplicationSpecific data for this user."
Dim ticket As FormsAuthenticationTicket = New FormsAuthenticationTicket(1, _
"username", _
DateTime.Now, _
DateTime.Now.AddMinutes(30), _
True, _
userData, _
FormsAuthentication.FormsCookiePath)
' Encrypt the ticket.
Dim encTicket As String = FormsAuthentication.Encrypt(ticket)
' Create the cookie.
Response.Cookies.Add(New HttpCookie(FormsAuthentication.FormsCookieName, encTicket))


L’IIS 7 deve essere impostato in modo da avere abilitate:
Autenticazione Anonima: Abilitato
Autenticazione basata su Form: Abilitato
Autenticazione di base: Disabilitato
Rappresentazione ASP.NET: Abilitato

L’IIS 5 deve essere impostato in modo da avere abilitate:

Accesso Anonimo: abilitato, il nome utente (ad esempio): IUSR_ServerTest e password quella di default, comunque quelli di default entrambi.
Autenticazione di Base: Disabilitato
Autenticazione Integrata di Windows: Abilitato

Paging e Sorting di un GridView

Con questi metodi è possibile gestire il paging e il sorting di un GridView non collegato ad un DataSource.

Private Property GridViewSortDirection() As String
Get
Return IIf(ViewState("SortDirection") = Nothing, "ASC", ViewState("SortDirection"))
End Get
Set(ByVal value As String)
ViewState("SortDirection") = value
End Set
End Property


Private Property GridViewSortExpression() As String
Get
Return IIf(ViewState("SortExpression") = Nothing, String.Empty, ViewState("SortExpression"))
End Get
Set(ByVal value As String)
ViewState("SortExpression") = value
End Set
End Property


Private Function GetSortDirection() As String
Select Case GridViewSortDirection
Case "ASC"
GridViewSortDirection = "DESC"
Case "DESC"
GridViewSortDirection = "ASC"
End Select
Return GridViewSortDirection
End Function


Protected Function SortDataTable(ByVal dataTable As DataTable, ByVal isPageIndexChanging As Boolean) As DataView
If Not dataTable Is Nothing Then
Dim dataView As New DataView(dataTable)
If GridViewSortExpression <> String.Empty Then
If isPageIndexChanging Then
dataView.Sort = String.Format("{0} {1}", GridViewSortExpression, GridViewSortDirection)
Else
dataView.Sort = String.Format("{0} {1}", GridViewSortExpression, GetSortDirection())
End If
End If
Return dataView
Else
Return New DataView()
End If
End Function

Nell'evento Paging viene passato al SortDataTable il datasource della griglia, che molto probabilmente sarà vuoto. E' conveniente salvare precedentemente il datasource nel viewState e poi passare tale campo al SortDataTable


Protected Sub gridAgenti_PageIndexChanging(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewPageEventArgs) Handles gridAgenti.PageIndexChanging
Try
gridAgenti.DataSource = SortDataTable(gridAgenti.DataSource, True)
gridAgenti.PageIndex = e.NewPageIndex
gridAgenti.DataBind()
Catch ex As Exception
Session.Remove("Exception")
Session.Add("Exception", ex)
Response.Redirect("ErrorPage.aspx")
End Try
End Sub

Protected Sub gridAgenti_Sorting(ByVal sender As Object, ByVal e As GridViewSortEventArgs) Handles gridAgenti.Sorting
GridViewSortExpression = e.SortExpression
Dim pageIndex As Integer = gridAgenti.PageIndex
gridAgenti.DataSource = SortDataTable(gridAgenti.DataSource, False)
gridAgenti.DataBind()
gridAgenti.PageIndex = pageIndex
End Sub