Control personalizado de ASP.NET: ¿cuál es la mejor manera de incluir referencias CSS incrustadas solo una vez?

El problema: estoy incrustando un archivo CSS en una biblioteca de control personalizada con varios controles. Quiero compartir el mismo archivo CSS para todos los controles, independientemente de cuántas instancias de ellos estén en un formulario dado. Cuando hay más de un control en el formulario, me gustaría exactamente 1 referencia al archivo CSS en el encabezado HTML de la página ASP.NET.

Esto es lo que se me ocurrió (hasta ahora):

Public Sub IncludeStyles(ByVal Page As System.Web.UI.Page)
    'Don't include the reference if it already exists...
    If Page.Header.FindControl("MyID") Is Nothing Then
        Dim cssUrl As String = Page.ClientScript.GetWebResourceUrl(GetType(Common), StylePath)

        Dim css As New System.Web.UI.HtmlControls.HtmlGenericControl("link")
        With css
            .Attributes.Add("rel", "stylesheet")
            .Attributes.Add("type", "text/css")
            .Attributes.Add("href", cssUrl)
            .ID = "MyID"
        End With

        Page.Header.Controls.Add(css)
    End If
End Sub

Ok, funciona ... pero el defecto obvio aquí es el uso deFindControl() para ver si el control existe en el formulario. Aunque estoy usando contenedores de nombres y todavía parece estar funcionando, estoy seguro de que hay alguna forma de romper esto. Agregar otro control en el formulario con la misma ID es seguramente uno ...

La pregunta: ¿Cuál es una mejor manera de garantizar que el control del encabezado solo se agregue al encabezado HTML exactamente una vez?

Nota laClientScript.RegisterClientScriptResource() El método tiene un parámetro que acepta un tipo .NET y este tipo se puede usar para garantizar que el código solo se muestre una vez por página. Lamentablemente, este método solo funciona con referencias de archivos JavaScript. Si hay un equivalente incorporado para las referencias CSS, esa sería mi preferencia.

Actualizar:

Descubrí una forma un poco más elegante de hacer estoaquí usando Page.ClientScript.RegisterClientScriptBlock y diciéndole que está incluyendo sus propias etiquetas de script, sin embargo, como señala Rick, esto no agrega el script a la etiqueta de encabezado html y tampoco es compatible con xhtml.

Actualización 2:

Vi otra idea interesante eneste hilo, pero recorrer la colección de controles no es una muy buena solución y agrega mucha sobrecarga si tiene varias referencias y varios controles en la página.

Chris Lively encontró una mejor solución que requiere menos código. Aquí está mi función alterada con la nueva solución:

Public Sub IncludeStyles(ByVal Page As System.Web.UI.Page)
    If Not Page.ClientScript.IsClientScriptBlockRegistered(StyleName) Then
        Dim cssUrl As String = Page.ClientScript.GetWebResourceUrl(GetType(Common), StylePath)

        Dim css As New System.Web.UI.HtmlControls.HtmlGenericControl("link")
        With css
            .Attributes.Add("href", cssUrl)
            .Attributes.Add("rel", "stylesheet")
            .Attributes.Add("type", "text/css")
        End With

        Page.Header.Controls.Add(css)
        Page.ClientScript.RegisterClientScriptBlock(GetType(Page), StyleName, "")
    End If
End Sub

Un par de cosas a tener en cuenta sobre esta solución. En su publicación original, Chris usó elIsClientScriptIncludeRegistered() método que no era el método correspondiente a laRegisterClientScriptBlock() método. Para que esta función funcione correctamente, la prueba debe hacerse conIsClientScriptBlockRegistered().

Además, preste especial atención al tipo que se pasa aRegisterClientScriptBlock(). Pasé un tipo de datos personalizado a este método (el mismo en todos mis controles), pero no se registró de tal manera que elIsClientScriptBlockRegistered() prueba funcionaría. Para que funcione, el objeto de página actual debe pasarse como el argumento Tipo.

Aunque es cierto que esta solución se siente un poco como un truco, a) no requiere mucho código o sobrecarga, b) produce exactamente el resultado deseado en la página, yc) es un código compatible con xhtml.

Respuestas a la pregunta(3)

Su respuesta a la pregunta