Design-time trouble with ASP.NET v2.0 Custom Control, with List<T> for child items - asp.net

Folks,
I am having a devil of a time with a custom control. The control is very simple - it just displays a list of "StepItems" (rendered as table rows), each with an icon. When I first drag it onto a page, and add StepItems to its collection, it renders perfectly. If I provide some text for its Header property, that also renders perfectly.
If I then look at the HTML source view, and then back to the design view, I get an error where my control should be. There are two kinds of errors:
If I set the .Header property, the error reads "StepProgressControl1:'someheadertext' could not be set on property 'Header'.
If I don't set the .Header, but add StepItems to the collection, I get this: "ErrorStepProgressControl1:'StepItems' could not be initialized. Details: Method not found: 'System.Collections.Generic.List`1 StepProgressControl.TKC.Experiment.StepProgressControl.get_StepItems()'."
The complete code for my custom control is below. If you can provide any help, thank you a great deal!
Tom
'================================
Imports System
Imports System.Collections
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Security.Permissions
Imports System.ComponentModel
Namespace TKC.Experiment
' THIS IS THE INTERNAL "CHILD" ELEMENT
< _
PersistenceMode(PersistenceMode.InnerProperty), _
TypeConverter(GetType(StepItemConverter)) _
> _
Public Class StepItem
Private _name As String
Public Sub New()
Me.New("")
End Sub
Public Sub New(ByVal name As String)
Me._name = name
End Sub
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
End Class
'=====================================================================
' THIS IS THE ACTUAL "PARENT" WEB CONTROL
< _
ParseChildren(True, "StepItems"), _
PersistChildren(False) _
> _
Public NotInheritable Class StepProgressControl
Inherits WebControl
Private _header As String = String.Empty
Private _stepItems As New List(Of StepItem)
Public Sub New()
Me.Header = "StepProgressControl"
End Sub
< _
PersistenceMode(PersistenceMode.Attribute) _
> _
Public Property Header() As String
Get
Return _header
End Get
Set(ByVal value As String)
_header = value
End Set
End Property
< _
DesignerSerializationVisibility(DesignerSerializationVisibility.Content), _
PersistenceMode(PersistenceMode.InnerProperty) _
> _
Public ReadOnly Property StepItems() As List(Of StepItem)
Get
If _stepItems Is Nothing Then
_stepItems = New List(Of StepItem)
End If
Return _stepItems
End Get
'Set(ByVal value As List(of stepitem))
' _stepItems = value
'End Set
End Property
Public Overrides Sub RenderControl(ByVal writer As System.Web.UI.HtmlTextWriter)
MyBase.RenderControl(writer)
Dim label As New Label()
label.Text = Header
label.RenderControl(writer)
Dim table As New Table()
Dim htr As New TableRow()
Dim hcell1 As New TableHeaderCell()
hcell1.Text = "Name"
htr.Cells.Add(hcell1)
Dim hcell2 As New TableHeaderCell()
hcell2.Text = "Title"
htr.Cells.Add(hcell2)
table.BorderWidth = Unit.Pixel(0)
Dim stepItem As StepItem
For Each stepItem In StepItems
Dim tr As New TableRow()
Dim cell1 As New TableCell()
Dim img As New HtmlImage
img.Src = ""
img.Alt = ""
cell1.Controls.Add(img)
tr.Cells.Add(cell1)
Dim cell2 As New TableCell()
cell2.Text = stepItem.Name
tr.Cells.Add(cell2)
table.Rows.Add(tr)
Next stepItem
table.RenderControl(writer)
End Sub
End Class
'========================================
'THIS IS A "TYPE CONVERTER" - JUST A COSMETIC THING, NOT CAUSING TROUBLE...
Public Class StepItemConverter
Inherits TypeConverter
Public Overloads Overrides Function ConvertTo(ByVal context As ITypeDescriptorContext, ByVal culture As System.Globalization.CultureInfo, ByVal value As Object, ByVal destinationType As Type) As Object
Dim obj As StepItem = DirectCast(value, StepItem)
Return obj.Name
End Function
End Class
End Namespace

You will want to implement your own Collection object to represent the list - otherwise the designer will not display it properly.
See the ICollection, IEnumerable, etc. interfaces.

Related

Why does RedirectToRoutePermanent add "count=0" to querystring?

I'm using ASP.NET 4.0 Routing and am reading route info from database and adding the routes as below. In a nutshell, my custom object "RouteLookup" contains the route information including the ID of another RouteLookup that it may or may not be redirected to. Here's an example of two RouteLookup entries in the db:
RouteLookupID RouteName RelativePath RequestHandler RouteHandler IsSecure RedirectedToRoute
13 PrivacyRoute about/privacy privacy.aspx NULL 0 0
14 PrivacyRoute1 privacy privacy.aspx NULL 0 13
RouteLookupID 14 is a legacy route that needs to be permanently redirected to RouteLookupID 13. The problem I'm running up against is when I request "http://mydomain.com/privacy" from the browser and watch Fiddler results, it actually redirects TWICE and adds a "count=0" as a querystring parameter! I have NO IDEA where this parameter is coming from as I have no process, httphandler, etc that is adding that explicitly.
What the heck is happening here? Any ideas are greatly appreciated and the rest of the relevant code is below.
I have a class, BaseRoute, which inherits from Route, so I can pass my custom RouteLookup object along with it to be examined in the custom RouteHandler which I've named BaseRouteHandler.
Public Class PageRouter
Private Shared db As New QADBDataContext
''''''' Is called from Global Application_Start
Public Shared Sub MapRoutes(routeColl As RouteCollection)
Dim routeLookups As IEnumerable(Of RouteLookup) = From rt In db.RouteLookups Select rt
For Each rtLookUp As RouteLookup In routeLookups
Dim parameterizedURL As String = BuildParameterizedVirtualPath(rtLookUp)
' Determine handler and route values
If rtLookUp.RouteHandler Is Nothing Then
RouteTable.Routes.Add(rtLookUp.RouteName, New BaseRoute(parameterizedURL, New BaseRouteHandler(), rtLookUp))
Else
RouteTable.Routes.Add(rtLookUp.RouteName, New BaseRoute(parameterizedURL, Activator.CreateInstance(Type.GetType("QA." + rtLookUp.RouteHandler)), rtLookUp))
End If
Next
End Sub
Protected Shared Function BuildParameterizedVirtualPath(rtLookUp As RouteLookup) As String
Dim parameterizedURL As String = rtLookUp.RelativePath
For Each param As RouteParameter In rtLookUp.RouteParameters
parameterizedURL &= "/{" + param.Name + "}"
Next
Return parameterizedURL
End Function
Public Shared Sub RedirectToRoutePermanent(rtData As RouteData)
Dim route As BaseRoute = DirectCast(rtData.Route, BaseRoute)
Dim rtLookup As RouteLookup = route.RouteLookup
Dim newRtLookupID As Integer = rtLookup.RedirectedToRoute
Dim newRtLookup As RouteLookup = (From rt In db.RouteLookups Where rt.RouteLookupID = newRtLookupID).SingleOrDefault
HttpContext.Current.Response.RedirectToRoutePermanent(newRtLookup.RouteName, rtData.Values.Values)
End Sub
End Class
Custom Route class:
Public Class BaseRoute
Inherits Route
Private _routeLookup As RouteLookup = Nothing
Public Sub New(url As String, routeHandler As IRouteHandler, routeLookup As RouteLookup)
MyBase.New(url, routeHandler)
_routeLookup = routeLookup
End Sub
Public ReadOnly Property RouteLookup As RouteLookup
Get
Return _routeLookup
End Get
End Property
End Class
Custom RouteHandler:
Public Class BaseRouteHandler
Implements IRouteHandler
Protected _baseRoute As BaseRoute = Nothing
Protected _rtLookup As RouteLookup = Nothing
Protected Overridable Sub InitializeContext(ByVal requestContext As System.Web.Routing.RequestContext)
_baseRoute = DirectCast(requestContext.RouteData.Route, BaseRoute)
_rtLookup = _baseRoute.RouteLookup
End Sub
Public Function GetHttpHandler(ByVal requestContext As System.Web.Routing.RequestContext) _
As System.Web.IHttpHandler Implements System.Web.Routing.IRouteHandler.GetHttpHandler
InitializeContext(requestContext)
EnforceURLStandard(requestContext)
PerformRedirectIfNeeded(requestContext)
Return GetPageHandler(requestContext)
End Function
Protected Overridable Sub PerformRedirectIfNeeded(ByVal requestContext As System.Web.Routing.RequestContext)
If _rtLookup.RedirectedToRoute > 0 Then
PageRouter.RedirectToRoutePermanent(requestContext.RouteData)
End If
End Sub
Protected Sub EnforceURLStandard(ByVal requestContext As System.Web.Routing.RequestContext)
' Test for:
' * Proper protocol
' * www. exists
' * must be all lowercase
Dim scheme As String = HttpContext.Current.Request.Url.GetComponents(UriComponents.Scheme, UriFormat.UriEscaped)
Dim rightSide As String = HttpContext.Current.Request.Url.GetComponents(UriComponents.HostAndPort Or UriComponents.PathAndQuery, UriFormat.UriEscaped)
Dim newURL As String = Nothing
If Not rightSide.ToLower().StartsWith("www.") AndAlso Not rightSide.ToLower().StartsWith("localhost") _
AndAlso Not rightSide.ToLower().StartsWith("uat") AndAlso Not rightSide.ToLower().StartsWith("ux") Then
newURL = scheme & "://www." & rightSide
End If
If _rtLookup.IsSecure <> requestContext.HttpContext.Request.IsSecureConnection Then
Dim newScheme As String = If(_rtLookup.IsSecure, "https", "http")
newURL = newScheme & rightSide
End If
Dim pattern As String = "[A-Z]"
If Not String.IsNullOrWhiteSpace(newURL) Then
If Regex.IsMatch(newURL, pattern) Then
newURL = newURL.ToLower()
End If
Else
If Regex.IsMatch(HttpContext.Current.Request.Url.ToString(), pattern) Then
newURL = HttpContext.Current.Request.Url.ToString().ToLower()
End If
End If
If Not newURL Is Nothing Then
HttpContext.Current.Response.RedirectPermanent(newURL, True)
End If
End Sub
Protected Overridable Function GetPageHandler(ByVal requestContext As System.Web.Routing.RequestContext) As System.Web.IHttpHandler
Return TryCast(BuildManager.CreateInstanceFromVirtualPath("/" & _rtLookup.RequestHandler, GetType(Page)), Page)
End Function
End Class
Well, figured out what was happening here. RedirectToRoutePermanent doesn't terminate the request like RedirectPermanent(url, true) does. I rewrote the PageRouter.RedirectToRoutePermanent as such, which resolved the issue:
Public Shared Sub RedirectToRoutePermanent(rtData As RouteData)
Dim route As BaseRoute = DirectCast(rtData.Route, BaseRoute)
Dim rtLookup As RouteLookup = route.RouteLookup
Dim newRtLookupID As Integer = rtLookup.RedirectedToRoute
Dim newRtLookup As RouteLookup = (From rt In db.RouteLookups Where rt.RouteLookupID = newRtLookupID).SingleOrDefault
Dim hostAndPort As String = HttpContext.Current.Request.Url.GetComponents(UriComponents.HostAndPort, UriFormat.UriEscaped)
Dim newURL As String = Nothing
Dim scheme As String = If(rtLookup.IsSecure, "https", "http")
newURL = scheme & "://" & hostAndPort
newURL &= "/" & newRtLookup.RelativePath
If rtData.Values.Count > 1 Then
For i As Integer = 1 To rtData.Values.Count - 1
newURL &= "/" & rtData.Values(i)
Next
End If
HttpContext.Current.Response.RedirectPermanent(newURL, True)
End Sub

Microsoft Translator for multiple textbox?

I get problem when use Microsoft Bing translator for show output on 3 labels for different languages.
Here is my code :
Imports System
Imports System.Collections.Generic
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Xml.Linq
Public Class AdmAccessToken
Public Property access_token() As String
Get
Return m_access_token
End Get
Set(ByVal value As String)
m_access_token = value
End Set
End Property
Private m_access_token As String
Public Property token_type() As String
Get
Return m_token_type
End Get
Set(ByVal value As String)
m_token_type = value
End Set
End Property
Private m_token_type As String
Public Property expires_in() As String
Get
Return m_expires_in
End Get
Set(ByVal value As String)
m_expires_in = value
End Set
End Property
Private m_expires_in As String
Public Property scope() As String
Get
Return m_scope
End Get
Set(ByVal value As String)
m_scope = value
End Set
End Property
Private m_scope As String
End Class
Partial Class translated
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
'Button1.Click += New EventHandler(Button1_Click1)
End Sub
Protected Sub Button1_Click1(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim clientID As String = "*******"
Dim clientSecret As String = "************"
Dim strTranslatorAccessURI As String = "https://datamarket.accesscontrol.windows.net/v2/OAuth2-13"
Dim strRequestDetails As String = String.Format("grant_type=client_credentials&client_id={0}&client_secret={1}&scope=http://api.microsofttranslator.com", HttpUtility.UrlEncode(clientID), HttpUtility.UrlEncode(clientSecret))
Dim webRequest As System.Net.WebRequest = System.Net.WebRequest.Create(strTranslatorAccessURI)
webRequest.ContentType = "application/x-www-form-urlencoded"
webRequest.Method = "POST"
Dim bytes As Byte() = System.Text.Encoding.ASCII.GetBytes(strRequestDetails)
webRequest.ContentLength = bytes.Length
Using outputStream As System.IO.Stream = webRequest.GetRequestStream()
outputStream.Write(bytes, 0, bytes.Length)
End Using
Dim webResponse As System.Net.WebResponse = webRequest.GetResponse()
Dim serializer As New System.Runtime.Serialization.Json.DataContractJsonSerializer(GetType(AdmAccessToken))
Dim token As AdmAccessToken = DirectCast(serializer.ReadObject(webResponse.GetResponseStream()), AdmAccessToken)
Dim headerValue As String = "Bearer " + token.access_token
Dim txtToTranslate As String = TextBox1.Text
Dim uri As String = "http://api.microsofttranslator.com/v2/Http.svc/Translate?text=" + System.Web.HttpUtility.UrlEncode(txtToTranslate) + "&from=en&to=es"
Dim translationWebRequest As System.Net.WebRequest = System.Net.WebRequest.Create(uri)
translationWebRequest.Headers.Add("Authorization", headerValue)
Dim response As System.Net.WebResponse = Nothing
response = translationWebRequest.GetResponse()
Dim stream As System.IO.Stream = response.GetResponseStream()
Dim encode As System.Text.Encoding = System.Text.Encoding.GetEncoding("utf-8")
Dim translatedStream As New System.IO.StreamReader(stream, encode)
Dim xTranslation As New System.Xml.XmlDocument()
xTranslation.LoadXml(translatedStream.ReadToEnd())
Label1.Text = "Your Translation is: " + xTranslation.InnerText
End Sub
End Class
Can anyone give some advice?
I just need to know how I can get translated text to 3 different label language: label 1 for dutch language, label 2 for english language, and label 3 for indonesian language.
The final chunk of code in your example does the translation from English to Spanish. (The part that starts with Dim txtToTranslate...)
You will have to just use that 3 times (put it in a function) with once doing a translation from your target language to Dutch, once to English, once to Indonesian.
The part where the translation is specified is this:
Dim uri As String = "http://api.microsofttranslator.com/v2/Http.svc/Translate?text=" + System.Web.HttpUtility.UrlEncode(txtToTranslate) + "&from=en&to=es"
From=en means 'from English'
To=es means 'to Spanish'
So just amend that for the languages you need...

Access sessions in asp.net handler

I am trying to upload images using generic handler as shown below and I have a normal aspx page where I am showing all the uploaded images after uploading.Everything is working fine.
<%# WebHandler Language="VB" Class="Upload"%>
Imports System
Imports System.Web
Imports System.Threading
Imports System.Web.Script.Serialization
Imports System.IO
Public Class Upload : Implements IHttpHandler, System.Web.SessionState.IRequiresSessionState
Public Class FilesStatus
Public Property thumbnail_url() As String
Public Property name() As String
Public Property url() As String
Public Property size() As Integer
Public Property type() As String
Public Property delete_url() As String
Public Property delete_type() As String
Public Property [error]() As String
Public Property progress() As String
End Class
Private ReadOnly js As New JavaScriptSerializer()
Private ingestPath As String
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim r = context.Response
ingestPath = context.Server.MapPath("~/UploadedImages/")
r.AddHeader("Pragma", "no-cache")
r.AddHeader("Cache-Control", "private, no-cache")
HandleMethod(context)
End Sub
Private Sub HandleMethod(ByVal context As HttpContext)
Select Case context.Request.HttpMethod
Case "HEAD", "GET"
ServeFile(context)
Case "POST"
UploadFile(context)
Case "DELETE"
DeleteFile(context)
Case Else
context.Response.ClearHeaders()
context.Response.StatusCode = 405
End Select
End Sub
Private Sub DeleteFile(ByVal context As HttpContext)
Dim filePath = ingestPath & context.Request("f")
If File.Exists(filePath) Then
File.Delete(filePath)
End If
End Sub
Private Sub ServeFile(ByVal context As HttpContext)
If String.IsNullOrEmpty(context.Request("f")) Then
ListCurrentFiles(context)
Else
DeliverFile(context)
End If
End Sub
Private Sub UploadFile(ByVal context As HttpContext)
Dim statuses = New List(Of FilesStatus)()
Dim headers = context.Request.Headers
If String.IsNullOrEmpty(headers("X-File-Name")) Then
UploadWholeFile(context, statuses)
Else
UploadPartialFile(headers("X-File-Name"), context, statuses)
End If
WriteJsonIframeSafe(context, statuses)
End Sub
Private Sub UploadPartialFile(ByVal fileName As String, ByVal context As HttpContext, ByVal statuses As List(Of FilesStatus))
If context.Request.Files.Count <> 1 Then
Throw New HttpRequestValidationException("Attempt to upload chunked file containing more than one fragment per request")
End If
Dim inputStream = context.Request.Files(0).InputStream
Dim fullName = ingestPath & Path.GetFileName(fileName)
Using fs = New FileStream(fullName, FileMode.Append, FileAccess.Write)
Dim buffer = New Byte(1023) {}
Dim l = inputStream.Read(buffer, 0, 1024)
Do While l > 0
fs.Write(buffer, 0, l)
l = inputStream.Read(buffer, 0, 1024)
Loop
fs.Flush()
fs.Close()
End Using
statuses.Add(New FilesStatus With {.thumbnail_url = "Thumbnail.ashx?f=" & fileName, .url = "Upload.ashx?f=" & fileName, .name = fileName, .size = CInt((New FileInfo(fullName)).Length), .type = "image/png", .delete_url = "Upload.ashx?f=" & fileName, .delete_type = "DELETE", .progress = "1.0"})
End Sub
Private Sub UploadWholeFile(ByVal context As HttpContext, ByVal statuses As List(Of FilesStatus))
For i As Integer = 0 To context.Request.Files.Count - 1
Dim file = context.Request.Files(i)
file.SaveAs(ingestPath & Path.GetFileName(file.FileName))
Thread.Sleep(1000)
Dim fname = Path.GetFileName(file.FileName)
statuses.Add(New FilesStatus With {.thumbnail_url = "Thumbnail.ashx?f=" & fname, .url = "Upload.ashx?f=" & fname, .name = fname, .size = file.ContentLength, .type = "image/png", .delete_url = "Upload.ashx?f=" & fname, .delete_type = "DELETE", .progress = "1.0"})
Next i
End Sub
Private Sub WriteJsonIframeSafe(ByVal context As HttpContext, ByVal statuses As List(Of FilesStatus))
context.Response.AddHeader("Vary", "Accept")
Try
If context.Request("HTTP_ACCEPT").Contains("application/json") Then
context.Response.ContentType = "application/json"
Else
context.Response.ContentType = "text/plain"
End If
Catch
context.Response.ContentType = "text/plain"
End Try
Dim jsonObj = js.Serialize(statuses.ToArray())
context.Response.Write(jsonObj)
End Sub
Private Sub DeliverFile(ByVal context As HttpContext)
Dim filePath = ingestPath & context.Request("f")
If File.Exists(filePath) Then
context.Response.ContentType = "application/octet-stream"
context.Response.WriteFile(filePath)
context.Response.AddHeader("Content-Disposition", "attachment, filename=""" & context.Request("f") & """")
Else
context.Response.StatusCode = 404
End If
End Sub
Private Sub ListCurrentFiles(ByVal context As HttpContext)
Dim files = New List(Of FilesStatus)()
Dim names = Directory.GetFiles(context.Server.MapPath("~/UploadedImages/"), "*", SearchOption.TopDirectoryOnly)
For Each name In names
Dim f = New FileInfo(name)
files.Add(New FilesStatus With {.thumbnail_url = "Thumbnail.ashx?f=" & f.Name, .url = "Upload.ashx?f=" & f.Name, .name = f.Name, .size = CInt(f.Length), .type = "image/png", .delete_url = "Upload.ashx?f=" & f.Name, .delete_type = "DELETE"})
Next name
context.Response.AddHeader("Content-Disposition", "inline, filename=""files.json""")
Dim jsonObj = js.Serialize(files.ToArray())
context.Response.Write(jsonObj)
context.Response.ContentType = "application/json"
End Sub
Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
End Class
Now I want to add a session variable by generating a random string and add the uploaded images to the newly created random string.
1.I have seen this Question on SO to use System.Web.SessionState.IRequiresSessionState for sessions and how do I create a folder with that and add my images to that folder after doing that how do I access this session variable in my normal aspx page.
2.(Or) the better way is create session variable in aspx page and pass that to handler?If so how can I do that?
3 .I am trying to find the control from my handler.Is that possible?If anyone knows how to get this then also my problem will get resolved so that I am trying to create a session from m aspx page.
Can anyone explain the better way of handling this situation.
I completely agree with jbl's comment.
You can get and set session using HttpContext.Current.Session anywhere on your project.
No matter where you create the session. Just make sure that the session exists before you access it.
Not sure what exactly you are asking here(need some more explanation).
Here is an example, where I used session on HttpHandler. However, it is on c#(hope you can understand).
This is not really an answer but #Knvn wrote a C# example which I couldn't understand so I used a converter to convert it to VB. Posted it here in case it helps someone in the future.
Public Class HttpHandler
Implements IHttpHandler
Implements IRequiresSessionState
Public Sub New()
End Sub
Public Sub ProcessRequest(context As HttpContext)
Dim Request As HttpRequest = context.Request
Dim Response As HttpResponse = context.Response
If SessionHandler.Current.UserID = 0 Then
Response.Redirect("~/Default.aspx")
Else
Try
If Request.Path.EndsWith(".pdf") Then
Dim client As New WebClient()
Dim buffer As [Byte]() = client.DownloadData(HttpContext.Current.Server.MapPath(Request.Path))
Response.ContentType = "application/pdf"
Response.AddHeader("content-length", buffer.Length.ToString())
Response.BinaryWrite(buffer)
Else
Using reader As New StreamReader(HttpContext.Current.Server.MapPath(Request.Path))
Response.Write(reader.ReadToEnd())
End Using
End If
Catch
Response.Redirect("~/Default.aspx")
End Try
End If
End Sub
Public ReadOnly Property IsReusable() As Boolean
' To enable pooling, return true here.
' This keeps the handler in memory.
Get
Return False
End Get
End Property
End Class

Looking for a Full S.DS.AM Sample with many AD extensions already written

System.DirectoryServices.AccountManagement can be extended to support additional properties for reading and writing AD properties.
Is anyone aware of a full/complete sample implementation that works for AD, Exchange 2003 or 2010?
There isn't anything online that I know of, but you are welcome to my collection (which I've included).
One thing you'll probably notice about my code is that I've almost completely replaced the standard get/set operations with my own code which writes directly to the underlying DirectoryEntry. This is because the built in set operation is not designed to handle data types which are arrays of arrays (such as the jpegPhoto attribute which is an array of byte arrays, with each byte array representing a picture).
First is a bunch of extension methods which I use for my various get/set operations.
''' <summary>
''' Checks if an attribute is available on the underlying object.
''' </summary>
<Extension()> _
Public Function IsAttributeDefined(ByVal prin As Principal, ByVal attribute As String) As Boolean
'since some attributes may not exist in all schemas check to see if it exists first
Dim uo As DirectoryEntry = DirectCast(prin.GetUnderlyingObject(), DirectoryEntry)
'check for property, if it's not found return an empty array
Return uo.Properties.Contains(attribute)
End Function
#Region "Get Helpers"
''' <summary>
''' This function is the foundation for retrieving data
''' </summary>
<Extension()> _
Public Function ExtensionGetAttributeObject(ByVal prin As Principal, ByVal attribute As String) As Object()
'check if the attribute exists on this object
If IsAttributeDefined(prin, attribute) Then
'if property exists then return the data
Dim dirObj As DirectoryEntry = prin.GetUnderlyingObject()
Dim val As Object() = (From c As Object In dirObj.Properties(attribute) Select c).ToArray()
Return val
Else
'return an empty array if the attribute is not defined
Return New Object(-1) {}
End If
End Function
''' <summary>
''' This is the primary function for retrieving attributes that contain only one value
''' </summary>
<Extension()> _
Public Function ExtensionGetSingleValue(ByVal prin As Principal, ByVal attribute As String) As Object
'get the object
Dim attributeValues() As Object = ExtensionGetAttributeObject(prin, attribute)
'if the item length = 1 then return the first value, else don't
If attributeValues.Length = 1 Then
Return attributeValues(0)
Else
Return Nothing
End If
End Function
''' <summary>
''' Returns the string value of an attribute
''' </summary>
''' <remarks>(null if no value found)</remarks>
<Extension()> _
Public Function ExtensionGetSingleString(ByVal prin As Principal, ByVal attribute As String) As String
Dim o As Object = ExtensionGetSingleValue(prin, attribute)
If o IsNot Nothing Then
Return o.ToString()
Else
Return String.Empty
End If
End Function
''' <summary>
''' Returns all of the strings contained in a multi-value attribute
''' </summary>
<Extension()> _
Public Function ExtensionGetMultipleString(ByVal prin As Principal, ByVal attribute As String) As String()
'get the object array for this attribute
Dim attributeValues() As Object = ExtensionGetAttributeObject(prin, attribute)
'create a string array of the same length as the object array
Dim array As String() = New String(attributeValues.Length - 1) {}
'and copy over all items, converting them to strings as we go
For i As Integer = 0 To attributeValues.Length - 1
array(i) = attributeValues(i).ToString()
Next
'return the string array
Return array
End Function
''' <summary>
''' Returns the date value of an attribute
''' </summary>
''' <remarks>(null if no value found)</remarks>
<Extension()> _
Public Function ExtensionGetSingleDate(ByVal prin As Principal, ByVal attribute As String) As String
Dim o As Object = ExtensionGetSingleValue(prin, attribute)
If o IsNot Nothing Then
Dim dt As DateTime = Convert.ToDateTime(o)
Return dt
Else
Return Nothing
End If
End Function
''' <summary>
''' Returns the principle represented by a column containing a single distinguished name
''' </summary>
<Extension()> _
Public Function ExtensionGetSingleDistinguishedName(ByVal prin As Principal, ByVal attribute As String) As Principal
'get the distinguished name of the object as a string
Dim dn As String = ExtensionGetSingleString(prin, attribute)
'check for null
If String.IsNullOrEmpty(dn) Then
Return Nothing
End If
'get the principal represented by the DN
Dim prinF As Principal = Principal.FindByIdentity(prin.Context, dn)
'if it exists then prepare to return it
If prinF IsNot Nothing Then
'if the object is a userprincipal then get the user detailed principal for it.
If TypeOf prinF Is UserPrincipal Then
prinF = UserDetailedPrinciple.FindByIdentity(prin.Context, prinF.Name)
End If
'return the principal
Return prinF
End If
'if all else fails return nothing
Return Nothing
End Function
<Extension()> _
Public Function ExtensionGetMultipleDistinguishedNames(ByVal prinParent As Principal, ByVal attribute As String) As Principal()
'get the distinguished name of the object as a string
Dim dn() As String = ExtensionGetMultipleString(prinParent, attribute)
'array to hold list of principles
Dim al As New List(Of Principal)()
For Each d As String In dn
'get the principal represented by the DN
Dim prin As Principal = Principal.FindByIdentity(prinParent.Context, d)
'if it exists then prepare to return it
If prin IsNot Nothing Then
'if the object is a userprincipal then get the user detailed principal for it.
If TypeOf prin Is UserPrincipal Then
prin = UserDetailedPrinciple.FindByIdentity(prin.Context, prin.Name)
ElseIf TypeOf prin Is GroupPrincipal Then
prin = GroupPrincipal.FindByIdentity(prin.Context, prin.Name)
End If
'return the principal
al.Add(prin)
End If
Next
'return list of principles
Return al.ToArray()
End Function
''' <summary>
''' Gets the bytes contained in an Octet String
''' </summary>
<Extension()> _
Public Function ExtentsionGetBytes(ByVal prin As Principal, ByVal attribute As String) As Byte()
'get the data
Dim o As Object = ExtensionGetSingleValue(prin, attribute)
'check for nulls
If o Is Nothing Then
Return Nothing
End If
'get the byte array
Dim byteArray() As Byte = DirectCast(o, Byte())
'return the data
Return byteArray
End Function
''' <summary>
''' Gets the image contained in an Octet String type attribute
''' </summary>
<Extension()> _
Public Function ExtensionGetImage(ByVal prin As Principal, ByVal attribute As String) As Image
'get bytes for attribute
Dim bytearray() As Byte = ExtentsionGetBytes(prin, attribute)
'if none returned return nothing
If bytearray Is Nothing Then
Return Nothing
End If
'read the bytes into a memory stream
Dim ms As New MemoryStream(bytearray)
'convert the memory stream to a bitmap and return it
Return New Bitmap(ms)
End Function
<Extension()> _
Public Function ExtensionGetImages(ByVal prin As Principal, ByVal attribute As String) As Image()
'get all values in attribute
Dim vals() As Object = ExtensionGetAttributeObject(prin, attribute)
'array to hold images to be returned
Dim al As New List(Of Image)()
For Each o As Object In vals
'get bytes
Dim bytearray() As Byte = DirectCast(o, Byte())
'if no data skip entry
If bytearray Is Nothing Then
Continue For
End If
'read the bytes into a memory stream
Dim ms As New MemoryStream(bytearray)
'convert the memory stream to a bitmap and add to the array
al.Add(New Bitmap(ms))
Next
'return the list of images as an array.
Return al.ToArray()
End Function
#End Region
#Region "Set Helpers"
Private Sub ExtensionSetDE(ByVal de As DirectoryEntry, ByVal attribute As String, ByVal value As Object)
'check value, if it's null then don't add (null means clear only)
If value IsNot Nothing Then
de.Properties(attribute).Add(value)
End If
End Sub
<Extension()> _
Public Sub ExtensionSetValue(ByVal prin As Principal, ByVal attribute As String, ByVal value As Object)
Dim uo As DirectoryEntry = prin.GetUnderlyingObject()
uo.Properties(attribute).Clear()
ExtensionSetDE(uo, attribute, value)
End Sub
<Extension()> _
Public Sub ExtensionSetStringValue(ByVal prin As Principal, ByVal attribute As String, ByVal value As String)
If String.IsNullOrEmpty(value) Then
value = Nothing
End If
ExtensionSetValue(prin, attribute, value)
End Sub
<Extension()> _
Public Sub ExtensionSetMultipleValueDirect(ByVal prin As Principal, ByVal attribute As String, ByVal values() As Object)
'Normal ExtensionSet does not support saving array type values (octet string)
' so we set it directly on the underlying object
Dim uo As DirectoryEntry = prin.GetUnderlyingObject()
uo.Properties(attribute).Clear()
If values IsNot Nothing Then
For Each v As Object In values
ExtensionSetDE(uo, attribute, v)
Next
End If
End Sub
<Extension()> _
Public Sub ExtensionSetImage(ByVal prin As Principal, ByVal attribute As String, ByVal img As Image)
'set data to attribute
ExtensionSetValue(prin, attribute, img.SaveImageToByteArray())
End Sub
<Extension()> _
Public Sub ExtensionSetImages(ByVal prin As Principal, ByVal attribute As String, ByVal img() As Image)
'array list to hold the values temporarily
Dim al As New ArrayList()
'convert each image into a byte array
For Each i As Image In img
al.Add(i.SaveImageToByteArray())
Next
'set image array as value on attribute
ExtensionSetMultipleValueDirect(prin, attribute, al.ToArray())
End Sub
<Extension()> _
Public Function SaveImageToByteArray(ByVal img As Image) As Byte()
'create a memory strea
Dim ms As New MemoryStream()
'write the image to the stream
img.Save(ms, Imaging.ImageFormat.Jpeg)
'save data to a byte array
Dim bytes() As Byte = ms.ToArray()
Return bytes
End Function
<Extension()> _
Public Sub ExtensionSetMultipleDistinguishedNames(ByVal prin As Principal, ByVal attribute As String, ByVal dns() As Principal)
'convert user principles into distinguished names
Dim sc As New ArrayList()
For Each u As UserDetailedPrinciple In dns
sc.Add(u.DistinguishedName)
Next
ExtensionSetMultipleValueDirect(prin, attribute, sc.ToArray())
End Sub
''' <summary>
''' Helps set the Thumbnail photo by resizing main photo and also saving original (possibly resized to 300xvariable)
''' to JpegPhoto.
''' </summary>
''' <param name="imgO">The iamge to use as the users thumbnail photo</param>
''' <remarks>You still NEED to call .Save() after calling this sub
''' as this sub does not call save().
''' </remarks>
<Extension()> _
Public Sub SetUserPhoto(ByVal prin As Principal, ByVal imgO As Image)
'resize the image for thumbnail
Dim imgN As Bitmap = ResizeImage(imgO, 100)
'check if we need to resize for medium sized image (300px high max
Dim imgM As Bitmap
If imgO.Height > 300 Then
imgM = ResizeImage(imgO, 300)
Else
imgM = imgO
End If
'save small image to the users profile
ExtensionSetImage(prin, "thumbnailPhoto", imgN)
'save original to the jpegPhoto attribute
ExtensionSetImages(prin, "jpegPhoto", New Image() {imgM})
End Sub
Private Function ResizeImage(ByVal imgO As Bitmap, ByVal Height As Integer) As Bitmap
'if the image is smaller/equal to the requested height return original
If imgO.Height <= Height Then
Return imgO
End If
'images are fixedHeightxVariable, so we need to calculate the variable portion
Dim width As Integer = (Convert.ToDecimal(imgO.Width) / Convert.ToDecimal(imgO.Height)) * Height
'resize the image
Dim imgN As New Bitmap(width, Height)
Dim g As Graphics = Graphics.FromImage(imgN)
g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
g.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
'draw in resized form
g.DrawImage(imgO, 0, 0, width, Height)
'return resized image
Return imgN
End Function
<Extension()> _
Public Function Rename(ByVal prin As Principal, ByVal NewName As String) As Principal
'escape commas
NewName = NewName.Replace(",", "\,")
'get directory object for move
Dim de As DirectoryEntry = prin.GetUnderlyingObject()
'move
de.Rename(String.Format("CN={0}", NewName))
de.CommitChanges()
'get the new object by name and return it
Return New ADConnection(prin.Context).GetPrincipalByName(prin.Guid.ToString())
End Function
#End Region
Here is the code in action in my custion UserPrinciple:
<DirectoryObjectClass("user")> _
<DirectoryRdnPrefix("CN")> _
Public Class UserDetailedPrinciple
Inherits UserPrincipal
<DirectoryProperty("initials")> _
Public Property MiddleInitial() As String
Get
Return ExtensionGetSingleString("initials")
End Get
Set(ByVal value As String)
ExtensionSetStringValue("initials", value)
End Set
End Property
<DirectoryProperty("wWWHomePage")> _
Public Property HomePage() As String
Get
Return ExtensionGetSingleString("wWWHomePage")
End Get
Set(ByVal value As String)
ExtensionSetStringValue("wWWHomePage", value)
End Set
End Property
<DirectoryProperty("url")> _
Public Property URLs() As String()
Get
Return ExtensionGetMultipleString("url")
End Get
Set(ByVal value As String())
ExtensionSetMultipleValueDirect("url", value)
End Set
End Property
<DirectoryProperty("info")> _
Public Property Notes() As String
Get
Return ExtensionGetSingleString("info")
End Get
Set(ByVal value As String)
ExtensionSetStringValue("info", value)
End Set
End Property
Public ReadOnly Property ObjectType() As String
Get
Dim types() As String = ExtensionGetMultipleString("objectClass")
Return types.Last()
End Get
End Property
<DirectoryProperty("thumbnailPhoto")> _
Public Property ThumbnailPhoto() As Image
Get
Return ExtensionGetImage("thumbnailPhoto")
End Get
Set(ByVal value As Image)
ExtensionSetImage("thumbnailPhoto", value)
End Set
End Property
<DirectoryProperty("thumbnailLogo")> _
Public Property ThumbnailLogo() As Image
Get
Return ExtensionGetImage("thumbnailLogo")
End Get
Set(ByVal value As Image)
ExtensionSetImage("thumbnailLogo", value)
End Set
End Property
<DirectoryProperty("jpegPhoto")> _
Public Property JpegPhoto() As Image()
Get
Return ExtensionGetImages("jpegPhoto")
End Get
Set(ByVal value As Image())
ExtensionSetImages("jpegPhoto", value)
End Set
End Property
<DirectoryProperty("title")> _
Public Property Title() As String
Get
Return ExtensionGetSingleString("title")
End Get
Set(ByVal value As String)
ExtensionSetStringValue("title", value)
End Set
End Property
<DirectoryProperty("department")> _
Public Property Department() As String
Get
Return ExtensionGetSingleString("department")
End Get
Set(ByVal value As String)
ExtensionSetStringValue("department", value)
End Set
End Property
<DirectoryProperty("company")> _
Public Property Company() As String
Get
Return ExtensionGetSingleString("company")
End Get
Set(ByVal value As String)
ExtensionSetStringValue("company", value)
End Set
End Property
<DirectoryProperty("manager")> _
Public Property Manager() As UserDetailedPrinciple
Get
Dim mgr As UserDetailedPrinciple = ExtensionGetSingleDistinguishedName("manager")
If mgr IsNot Nothing Then
If Me.Guid <> mgr.Guid Then
Return mgr
End If
End If
Return Nothing
End Get
Set(ByVal value As UserDetailedPrinciple)
'check for nulls
If value Is Nothing Then
ExtensionSetStringValue("manager", Nothing)
Else
ExtensionSetStringValue("manager", value.DistinguishedName)
End If
End Set
End Property
<DirectoryProperty("assistant")> _
Public Property Assistant() As UserDetailedPrinciple
Get
Dim assist As UserDetailedPrinciple = ExtensionGetSingleDistinguishedName("assistant")
If assist IsNot Nothing Then
Return assist
End If
Return Nothing
End Get
Set(ByVal value As UserDetailedPrinciple)
'check for nulls
If value Is Nothing Then
ExtensionSetStringValue("assistant", Nothing)
Else
ExtensionSetStringValue("assistant", value.DistinguishedName)
End If
End Set
End Property
<DirectoryProperty("directReports")> _
Public Property DirectReports() As Principal()
Get
Dim dReports As Principal() = ExtensionGetMultipleDistinguishedNames("directReports")
Return dReports
End Get
Set(ByVal value As Principal())
ExtensionSetMultipleDistinguishedNames("directReports", value)
End Set
End Property
<DirectoryProperty("homePhone")> _
Public Property HomePhone() As String
Get
Return ExtensionGetSingleString("homePhone")
End Get
Set(ByVal value As String)
ExtensionSetStringValue("homePhone", value)
End Set
End Property
<DirectoryProperty("pager")> _
Public Property Pager() As String
Get
Return ExtensionGetSingleString("pager")
End Get
Set(ByVal value As String)
ExtensionSetStringValue("pager", value)
End Set
End Property
<DirectoryProperty("otherTelephone")> _
Public Property OtherTelephone() As String()
Get
Return ExtensionGetMultipleString("otherTelephone")
End Get
Set(ByVal value As String())
ExtensionSetMultipleValueDirect("otherTelephone", value)
End Set
End Property
<DirectoryProperty("physicalDeliveryOfficeName")> _
Public Property PhysicalLocation() As String
Get
Return ExtensionGetSingleString("physicalDeliveryOfficeName")
End Get
Set(ByVal value As String)
ExtensionSetStringValue("physicalDeliveryOfficeName", value)
End Set
End Property
<DirectoryProperty("l")> _
Public Property AddressCity() As String
Get
Return ExtensionGetSingleString("l")
End Get
Set(ByVal value As String)
ExtensionSetStringValue("l", value)
End Set
End Property
<DirectoryProperty("postOfficeBox")> _
Public Property AddressPOBox() As String
Get
Return ExtensionGetSingleString("postOfficeBox")
End Get
Set(ByVal value As String)
ExtensionSetStringValue("postOfficeBox", value)
End Set
End Property
<DirectoryProperty("st")> _
Public Property AddressState() As String
Get
Return ExtensionGetSingleString("st")
End Get
Set(ByVal value As String)
ExtensionSetStringValue("st", value)
End Set
End Property
<DirectoryProperty("streetAddress")> _
Public Property Address() As String
Get
Return ExtensionGetSingleString("streetAddress")
End Get
Set(ByVal value As String)
ExtensionSetStringValue("streetAddress", value)
End Set
End Property
<DirectoryProperty("postalCode")> _
Public Property AddressZipCode() As String
Get
Return ExtensionGetSingleString("postalCode")
End Get
Set(ByVal value As String)
ExtensionSetStringValue("postalCode", value)
End Set
End Property
<DirectoryProperty("c")> _
Public Property AddressCountry() As String
Get
Return ExtensionGetSingleString("c")
End Get
Set(ByVal value As String)
ExtensionSetStringValue("c", value)
End Set
End Property
<DirectoryProperty("whenCreated")> _
Public ReadOnly Property Created() As Nullable(Of DateTime)
Get
Return ExtensionGetSingleDate("whenCreated")
End Get
End Property
<DirectoryProperty("whenChanged")> _
Public ReadOnly Property LastModified() As Nullable(Of DateTime)
Get
Return ExtensionGetSingleDate("whenChanged")
End Get
End Property
Public Sub New()
MyBase.New(ADConnection.CurrentADPrincipalContext)
End Sub
Public Sub New(ByVal context As PrincipalContext)
MyBase.New(context)
End Sub
Public Overloads Shared Function FindByIdentity(ByVal context As PrincipalContext, ByVal identityValue As String) As UserDetailedPrinciple
Return DirectCast(Principal.FindByIdentityWithType(context, GetType(UserDetailedPrinciple), identityValue), UserDetailedPrinciple)
End Function
Public Overloads Shared Function FindByIdentity(ByVal context As PrincipalContext, ByVal identityType As IdentityType, ByVal identityValue As String) As UserDetailedPrinciple
Return DirectCast(Principal.FindByIdentityWithType(context, GetType(UserDetailedPrinciple), identityType, identityValue), UserDetailedPrinciple)
End Function
End Class

How to hide a node from appearing on menu not on breadcrumb (using SqlSiteMapProvider)

I am using wicked code sqlsitemapprovider or it's VB version. Most of the things are going OK! But when I wanted to hide some of the nodes from appearing on menu while staying shown on sitemappath I cannot figure it out. I tried to change the sqlsitemapprovider code but was unsuccessfull. I have found David Sussman's (from sp.net) answer. but it was for a .sitemap file. So how can I manage to do the same with the sql sitemap provider mentioned above.
I added a column named visible to my SiteMap table it's type is bit and then I have done these changes (Sorry for such long code):
Imports System
Imports System.Web
Imports System.Data.SqlClient
Imports System.Collections.Specialized
Imports System.Configuration
Imports System.Web.Configuration
Imports System.Collections.Generic
Imports System.Configuration.Provider
Imports System.Security.Permissions
Imports System.Data.Common
Imports System.Data
Imports System.Web.Caching
''' <summary>
''' Summary description for SqlSiteMapProvider
''' </summary>
<SqlClientPermission(SecurityAction.Demand, Unrestricted:=True)> _
Public Class SqlSiteMapProvider
Inherits StaticSiteMapProvider
Private Const _errmsg1 As String = "Basamak no bulunamadı"
Private Const _errmsg2 As String = "Çift Basamak No"
Private Const _errmsg3 As String = "Üst Basamak Bulunamadı"
Private Const _errmsg4 As String = "Hatalı Üst Basamak"
Private Const _errmsg5 As String = "Bağlantı dizesi bulunamadı veya boş"
Private Const _errmsg6 As String = "Bağlantı dizesi bulunamadı"
Private Const _errmsg7 As String = "Bağlantı dizesi boş"
Private Const _errmsg8 As String = "Hatalı sqlCacheDependency"
Private Const _cacheDependencyName As String = "__SiteMapCacheDependency"
Private _connect As String
'Database connection string
Private _database As String, _table As String
'Database info for SQL Server 7/2000 cache dependency
Private _2005dependency As Boolean = False
'Database info for SQL Server 2005 cache dependency
Private _indexID As Integer, _indexTitle As Integer, _indexUrl As Integer, _indexDesc As Integer, _indexRoles As Integer, _indexParent As Integer, _indexvisible As Boolean
Private _nodes As New Dictionary(Of Integer, SiteMapNode)(16)
Private ReadOnly _lock As New Object()
Private _root As SiteMapNode
'Added...Declare an arraylist to hold all the roles this menu item applies to
Public roles As New ArrayList
Public Overloads Overrides Sub Initialize(ByVal name As String, ByVal config As NameValueCollection)
'Verify that config isn't null
If config Is Nothing Then
Throw New ArgumentNullException("config")
End If
'Assign the provider a default name if it doesn't have one
If [String].IsNullOrEmpty(Name) Then
Name = "SqlSiteMapProvider"
End If
' Add a default "description" attribute to config if the
' attribute doesnt exist or is empty
If String.IsNullOrEmpty(config("description")) Then
config.Remove("description")
config.Add("description", "SQL site map provider")
End If
' Call the base class's Initialize method
MyBase.Initialize(Name, config)
' Initialize _connect
Dim connect As String = config("connectionStringName")
If [String].IsNullOrEmpty(connect) Then
Throw New ProviderException(_errmsg5)
End If
config.Remove("connectionStringName")
If WebConfigurationManager.ConnectionStrings(connect) Is Nothing Then
Throw New ProviderException(_errmsg6)
End If
_connect = WebConfigurationManager.ConnectionStrings(connect).ConnectionString
If [String].IsNullOrEmpty(_connect) Then
Throw New ProviderException(_errmsg7)
End If
' Initialize SQL cache dependency info
Dim dependency As String = config("sqlCacheDependency")
If Not [String].IsNullOrEmpty(dependency) Then
If [String].Equals(dependency, "CommandNotification", StringComparison.InvariantCultureIgnoreCase) Then
SqlDependency.Start(_connect)
_2005dependency = True
Else
' If not "CommandNotification", then extract database and table names
Dim info As String() = dependency.Split(New Char() {":"c})
If info.Length <> 2 Then
Throw New ProviderException(_errmsg8)
End If
_database = info(0)
_table = info(1)
End If
config.Remove("sqlCacheDependency")
End If
' SiteMapProvider processes the securityTrimmingEnabled
' attribute but fails to remove it. Remove it now so we can
' check for unrecognized configuration attributes.
If config("securityTrimmingEnabled") IsNot Nothing Then
config.Remove("securityTrimmingEnabled")
End If
' Throw an exception if unrecognized attributes remain
If config.Count > 0 Then
Dim attr As String = config.GetKey(0)
If Not [String].IsNullOrEmpty(attr) Then
Throw New ProviderException("Unrecognized attribute: " + attr)
End If
End If
End Sub
Public Overloads Overrides Function BuildSiteMap() As SiteMapNode
SyncLock _lock
' Return immediately if this method has been called before
If _root IsNot Nothing Then
Return _root
End If
' Query the database for site map nodes
Dim connection As New SqlConnection(_connect)
Try
Dim command As New SqlCommand("proc_GetSiteMap", connection)
command.CommandType = CommandType.StoredProcedure
' Create a SQL cache dependency if requested
Dim dependency As SqlCacheDependency = Nothing
If _2005dependency Then
dependency = New SqlCacheDependency(command)
ElseIf Not [String].IsNullOrEmpty(_database) AndAlso Not String.IsNullOrEmpty(_table) Then
dependency = New SqlCacheDependency(_database, _table)
End If
connection.Open()
Dim reader As SqlDataReader = command.ExecuteReader()
_indexID = reader.GetOrdinal("ID")
_indexUrl = reader.GetOrdinal("Url")
_indexTitle = reader.GetOrdinal("Title")
_indexDesc = reader.GetOrdinal("Description")
_indexRoles = reader.GetOrdinal("Roles")
_indexParent = reader.GetOrdinal("Parent")
_indexvisible = reader.GetOrdinal("visible")
If reader.Read() Then
' Create the root SiteMapNode and add it to the site map
_root = CreateSiteMapNodeFromDataReader(reader)
AddNode(_root, Nothing)
' Build a tree of SiteMapNodes underneath the root node
While reader.Read()
' Create another site map node and add it to the site map
Dim node As SiteMapNode = CreateSiteMapNodeFromDataReader(reader)
AddNode(node, GetParentNodeFromDataReader(reader))
End While
' Use the SQL cache dependency
If dependency IsNot Nothing Then
HttpRuntime.Cache.Insert(_cacheDependencyName, New Object(), dependency, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, _
New CacheItemRemovedCallback(AddressOf OnSiteMapChanged))
End If
End If
Finally
connection.Close()
End Try
' Return the root SiteMapNode
Return _root
End SyncLock
End Function
Protected Overloads Overrides Function GetRootNodeCore() As SiteMapNode
SyncLock _lock
BuildSiteMap()
Return _root
End SyncLock
End Function
' Helper methods
Private Function CreateSiteMapNodeFromDataReader(ByVal reader As DbDataReader) As SiteMapNode
' Make sure the node ID is present
If reader.IsDBNull(_indexID) Then
Throw New ProviderException(_errmsg1)
End If
' Get the node ID from the DataReader
Dim id As Integer = reader.GetInt32(_indexID)
' Make sure the node ID is unique
If _nodes.ContainsKey(id) Then
Throw New ProviderException(_errmsg2)
End If
' Get title, URL, description, and roles from the DataReader
Dim title As String = IIf(reader.IsDBNull(_indexTitle), Nothing, reader.GetString(_indexTitle).Trim())
'Dim url As String = IIf(reader.IsDBNull(_indexUrl), Nothing, reader.GetString(_indexUrl).Trim())
'Dim url As String = ReplaceNullRefs(reader, _indexUrl)
Dim url As String = String.Empty
If Not (reader.IsDBNull(_indexUrl)) Then
url = reader.GetString(_indexUrl).Trim()
Else
url = ""
End If
'Eliminated...see http://weblogs.asp.net/psteele/archive/2003/10/09/31250.aspx
'Dim description As String = IIf(reader.IsDBNull(_indexDesc), Nothing, reader.GetString(_indexDesc).Trim())
'Added line below and 'ReplaceNUllRefs' func
Dim description As String = ReplaceNullRefs(reader, _indexDesc)
'Changed variable name from 'roles' to 'rolesN' and added line 230 to dump all roles into an arrayList
Dim rolesN As String = IIf(reader.IsDBNull(_indexRoles), Nothing, reader.GetString(_indexRoles).Trim())
Dim rolelist As String() = Nothing
If Not [String].IsNullOrEmpty(rolesN) Then
rolelist = rolesN.Split(New Char() {","c, ";"c}, 512)
End If
roles = ArrayList.Adapter(rolelist)
Dim visible As Boolean = ReplaceNullRefs(reader, _indexvisible)
' Create a SiteMapNode
Dim node As New SiteMapNode(Me, id.ToString(), url, title, description, rolelist, _
Nothing, Nothing, Nothing)
' Record the node in the _nodes dictionary
_nodes.Add(id, node)
' Return the node
Return node
End Function
Private Function ReplaceNullRefs(ByVal rdr As SqlDataReader, ByVal rdrVal As Integer) As String
If Not (rdr.IsDBNull(rdrVal)) Then
Return rdr.GetString(rdrVal)
Else
Return String.Empty
End If
End Function
Private Function GetParentNodeFromDataReader(ByVal reader As DbDataReader) As SiteMapNode
' Make sure the parent ID is present
If reader.IsDBNull(_indexParent) Then
'**** Commented out throw, added exit function ****
Throw New ProviderException(_errmsg3)
'Exit Function
End If
' Get the parent ID from the DataReader
Dim pid As Integer = reader.GetInt32(_indexParent)
' Make sure the parent ID is valid
If Not _nodes.ContainsKey(pid) Then
Throw New ProviderException(_errmsg4)
End If
' Return the parent SiteMapNode
Return _nodes(pid)
End Function
Private Sub OnSiteMapChanged(ByVal key As String, ByVal item As Object, ByVal reason As CacheItemRemovedReason)
SyncLock _lock
If key = _cacheDependencyName AndAlso reason = CacheItemRemovedReason.DependencyChanged Then
' Refresh the site map
Clear()
_nodes.Clear()
_root = Nothing
End If
End SyncLock
End Sub
End Class
and I get this error:
*Özel Durum Ayrıntıları: System.IndexOutOfRangeException: visible
Kaynak Hatası:
Satır 154: _indexRoles = reader.GetOrdinal("Roles")
Satır 155: _indexParent = reader.GetOrdinal("Parent")
Satır 156: _indexvisible = reader.GetOrdinal("visible")
Satır 157:
Satır 158: If reader.Read() Then
Kaynak Dosya: D:\Websites\kaihl\App_Code\SqlSiteMapProvider.vb Satır: 156*
What I want is to tell sqlsitemapprovider to include an attribute within each sitemapnode called visible="true/false". Since this will be an extra attribute for sitemappath and menu (I think) this code would be doing the hiding job in menu not in breadcrumb (according to David Sussman's reply to a similar files .sitemap based thread as I linked above in my question):
Protected Sub Menu1_MenuItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.MenuEventArgs) Handles Menu1.MenuItemDataBound
Dim node As SiteMapNode = CType(e.Item.DataItem, SiteMapNode)
' check for the visible attribute and if false
' remove the node from the parent
' this allows nodes to appear in the SiteMapPath but not show on the menu
If Not String.IsNullOrEmpty(node("visible")) Then
Dim isVisible As Boolean
If Boolean.TryParse(node("visible"), isVisible) Then
If Not isVisible Then
e.Item.Parent.ChildItems.Remove(e.Item)
End If
End If
End If
End Sub
how to achieve this? thank you.
Update: I have found something very close at this page but still unable to deploy the solution.
Dim atts As NameValueCollection = Nothing
Dim attributeString As String = reader("attributes").ToString().Trim()
If Not String.IsNullOrEmpty(attributeString) Then
atts = New NameValueCollection()
Dim attributePairs() As String = attributeString.Split(";")
For Each attributePair As String In atts
Dim attributes() As String = attributePair.Split(":")
If attributes.Length = 2 Then
atts.Add(atts(0), attributes(1))
End If
Next
End If
Dim node As New SiteMapNode(Me, id.ToString(), url, title, description, rolelist, _
atts, Nothing, Nothing)
At last I have found a solution. And it is here. Thanks so much to Kadir ÖZGÜR, Sanjay UTTAM, David Sussman.
Checkout this link. he overides the IsAccessibleToUser property on the SiteMapprovider to selectivly show nodes based on the role of the current user. you caould change the condiftion to suit your needs.

Resources