Scrambling URLS for dynamic data - asp.net

What is the best method to obfuscate the urls created in Dynamic Data?
eg \Products\List.aspx?ProductId=2 could become
\Products\List.aspx?x=UHJvZHVjdElkPTI=
where "ProductId=2" is base 64 encoded to prevent casual snooping on
\Products\List.aspx?ProductId=3
\Products\List.aspx?ProductId=4
etc...?
I will probably have to inherit from an existing object and override some function
The question is which object and what function
GetActionPath of the Metamodel object seems interesting,
but how does the DynamicRoute "{table}/{Action}.aspx" play in into it...
Right now on Asp.net 1.1 site I use an custom implementation of the following code.
http://www.mvps.org/emorcillo/en/code/aspnet/qse.shtml It is HTTPModule that uses regular expression to rewrite all the querystrings and also with reflection changes the Querystring collection with decoded values.
So where is the hook to affect the change.

I have found the solution
With advice, I have implemented a Route that inherits from DynamicDataRoute.
The methods overridden were GetVirtualPath and GetRouteData.
Here is the global.asax page
routes.Add(New EncodedDynamicDataRoute("{table}/{action}.aspx") With { _
.Defaults = New RouteValueDictionary(New With {.Action = PageAction.List}), _
.Constraints = New RouteValueDictionary(New With {.Action "List|Details|Edit|Insert"}), _
.Model = model})
Here is the Encoded DynamicDataRoute.
Imports System.Web.DynamicData
Imports System.Web.Routing
''' <summary>
''' The purpose of this class to base 64 encode the querystring parameters.
''' It converts the keys to base64 encoded and back.
''' </summary>
Public Class EncodedDynamicDataRoute
Inherits DynamicDataRoute
Public Sub New(ByVal url As String)
MyBase.New(url)
End Sub
Public Overloads Overrides Function GetRouteData(ByVal httpContext As HttpContextBase) As RouteData
Dim routeData As RouteData = MyBase.GetRouteData(httpContext)
If Not (routeData Is Nothing) Then
DecodeRouteValues(routeData.Values)
End If
Return routeData
End Function
Private Sub EncodeRouteValues(ByVal routeValues As RouteValueDictionary)
Dim tableName As Object
If Not routeValues.TryGetValue("table", tableName) Then
Return
End If
Dim table As MetaTable
If Not Model.TryGetTable(DirectCast(tableName, String), table) Then
Return
End If
Dim strOutput As New StringBuilder
Dim val As Object
For Each column As MetaColumn In table.PrimaryKeyColumns
If routeValues.TryGetValue(column.Name, val) Then
strOutput.Append(column.Name & Chr(254) & val & Chr(255))
routeValues.Remove(column.Name)
End If
Next
Dim out As String = (Convert.ToBase64String(Encoding.ASCII.GetBytes(strOutput.ToString)))
If routeValues.ContainsKey("x") Then
routeValues.Item("x") = out
Else
routeValues.Add("x", out)
End If
End Sub
Public Overloads Overrides Function GetVirtualPath(ByVal requestContext As RequestContext, ByVal values As RouteValueDictionary) As VirtualPathData
EncodeRouteValues(values)
Return MyBase.GetVirtualPath(requestContext, values)
End Function
Private Sub DecodeRouteValues(ByVal routeValues As RouteValueDictionary)
Dim tableName As Object
If Not routeValues.TryGetValue("table", tableName) Then
Return
End If
Dim table As MetaTable
If Not Model.TryGetTable(DirectCast(tableName, String), table) Then
Return
End If
Dim enc As New System.Text.ASCIIEncoding()
Dim val As Object
If routeValues.TryGetValue("x", val) AndAlso val <> "AAA" Then
Dim strString As String = enc.GetString(Convert.FromBase64String((val)))
Dim nameValuePairs As String() = strString.Split(Chr(255))
Dim col As MetaColumn
For Each str11 In nameValuePairs
Dim vals() As String = str11.Split(Chr(254))
If table.TryGetColumn(vals(0), col) Then
routeValues.Add(val(0), col)
End If
Next
End If
End Sub
End Class

Here is how I did it:
I created 4 functions in a module:
public static string EncryptInt(int val)
public static int DecryptInt(string val)
public static string DecryptStr(string str)
public static string EncryptStr(string source)
When I wanted to create a url I did something like this:
string.Format(#"\path\file.aspx?ID={0}&name={1}",encrypt.EncryptInt(inID),encrypt.EncriptStr(inName));
When I wanted to get the results I would call the Decrypt function on retrieved param.
I used two types because it added a level of type safety to the system, but you could just use one with strings and then call int.Parse() as needed.
Does this answer your question?
For Microsoft's Dynamic Data I believe the hooks would be found in the code behind for the template pages.

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

Returning multiple values from a function in an parcial class in VB

Hi Please can someone show me how to return multiple values from a function? I have my function in a seperate file within App_Code and here it is:
Public Function GetQuoteStatus(ByVal QuoteID As String) As String
Dim quoteStatus As String
Dim con As New SqlConnection
Dim cmd As New SqlCommand
Try
con.ConnectionString = ConfigurationManager.AppSettings("quotingSystemConnectionString")
con.Open()
cmd.Connection = con
cmd.CommandText = "SELECT Status FROM Quote WHERE QuoteID =" & QuoteID & ";"
Dim lrd As SqlDataReader = cmd.ExecuteReader()
While lrd.Read()
quoteStatus = lrd("Status")
End While
Catch ex As Exception
Finally
con.Close()
End Try
Return quoteStatus
End Function
To get the returned quoteStatus from within another vb file in my site I would normally use:
Dim statusHelper As New quoteStatusHelper()
Dim quoteStatus As String = statusHelper.GetQuoteStatus("QuoteID")
However this is all good and well for one returned value but what If I wanted to return multiple values... How do I access them?
Many thanks!
You could use
Public Function GetQuoteStatus(ByVal QuoteID As String) As String()
This let you return a string array, so there is no limit to data you can have.
The cons is you have to parse the array.
You could even use
Public Function GetQuoteStatus(ByVal QuoteID As String,
Byref Second As String) As String
This let you return a string as result and set the value of another var (Second); you can use more than one Byref variables to return multiple values...
The cons is that you have to statically declare your function and modifiy all previous calls. In this case the use of refactoring is reccomended!
EDITED:
You could even return a class for example.
Declare a class that fits your needs (with all the fields, getters, setters and constructors) and inside your function you could create an instance of that class, fill every field and return this class.
Easy to implement, easy to use.
EDITED AGAIN:
Public Class MyClass
Public Property Val1 As String
Public Property Val2 As String
Public Property Val3 As String
Public Sub New(ByVal newVal1 As String, ByVal newVal2 As String, ByVal newVal3 As String)
Val1 = newVal1
Val2 = newVal2
Val3 = newVal3
End Sub
End Class
Public Function GetInfo() As MyClass
Dim mc As New MyClass("test1", "test2", "test3")
Return mc
End Function
You may return multiple values using ByRef and arrays (see #Marco post). You may also return/pass an object for your purpose.
For instance,
Public Class Info
Public Property No As Integer
Public Property Name As String
End Class
....
Public Function GetInfo() As Info
Dim inf As New Info
inf.No = 10
inf.Name = "A"
Return inf
End Function
....
I believe that the "correct/best" way to deal with a single function that needs to return a couple of discrete (typically primitive) types is a Tuple(Of T1, T2, T3, T4, T5, T6, T7, TRest).
Something like this
Public Function MyExampleMethod() As Tuple(Of String, Integer, Guid)
Return New Tuple(Of String, Integer, Guid)("Value1", 2, Guid.NewGuid)
End Function

SQL Dataset to JSON

Alright I have been trying to figure this out and I read the MSDN page on the JavaScriptSerializer. However, I still can't figure out how to get this to work on an asp.net page. I want to convert my dataset into a json string so I can graph it using FLOT(graphing tool)
THIS MADE IT WORK THANKS FOR YOUR HELP GUYS: this is in vb.net for future people
Imports System.Web.Script.Serialization
....
Dim myObject = dataset.GetXml()
Dim jsonString = (New JavaScriptSerializer()).Serialize(myObject)
Reference the assembly System.Web.Extensions.dll and then do this:
using System.Web.Script.Serialization;
....
var myObject = ... your stuff ...
var jsonString = new JavaScriptSerializer().Serialize(myObject);
Check out the MSDN page for more info.
I did the following when I was working on a Project using PlotKit. I create a webservice to return the data and set the response format to Jason...this was while ago...should also work in 3.5
Here is a sample
<WebMethod()> _
<Script.Services.ScriptMethod(UseHttpGet:=True, ResponseFormat:=ResponseFormat.Json)> _
Public Function GetSales(ByVal a As String) As Generic.List(Of Sale)
Dim _conn As SqlConnection = New SqlConnection(connstr)
Dim _dr As SqlDataReader
Try
Dim _cmd As SqlCommand = New SqlCommand("select * from sales", _conn)
_conn.Open()
_dr = _cmd.ExecuteReader(CommandBehavior.CloseConnection)
If _dr.HasRows Then
Dim s As Sale
Dim c As New Generic.List(Of Sale)
While _dr.Read
s = New Sale
With s
.Month = _dr("monthname")
.TheSale = _dr("sale")
End With
c.Add(s)
End While
Return c
End If
Catch ex As Exception
MsgBox(ex.Message)
Finally
_conn.Close()
End Try
End Function
End Class
Here is the object class...notice I am serializing the object.
<Serializable()> _
Public Class Sale
Private _month As String
Private _sale As String
Public Property Month() As String
Get
Return _month
End Get
Set(ByVal value As String)
_month = value
End Set
End Property
Public Property TheSale() As String
Get
Return _sale
End Get
Set(ByVal value As String)
_sale = value
End Set
End Property
End Class
Check out the DataContractJsonSerializer, and this article on MSDN
public static string DStoJSON(DataSet ds)
{
StringBuilder json = new StringBuilder();
foreach (DataRow dr in ds.Tables[0].Rows)
{
json.Append("{");
int i = 0;
int colcount = dr.Table.Columns.Count;
foreach (DataColumn dc in dr.Table.Columns)
{
json.Append("\"");
json.Append(dc.ColumnName);
json.Append("\":\"");
json.Append(dr[dc]);
json.Append("\"");
i++;
if (i < colcount) json.Append(",");
}
json.Append("\"}");
json.Append(",");
}
return json.ToString();
}
Probably most useful to you is the dataset loop instead of the stringbuilder. You could loop these into an object, then use the javascript serializer library.
Or even better, if you are using asp.net mvc, you can just do this:
return Json(List<myobject>, JsonRequestBehavior.AllowGet);
but this way is quick & easy! -- I didn't quite test this! the appended comma might be wrong (or code can be improved) and the final row comma needs to be handled
I use the mvc way & never looked back :)

Consume ASMX Webservice From Classic ASP Using SOAP Client 3.0

I made a webservice in VB.Net with a method returning a custom class or object.
<WebMethod()> _
Public Function CreatePerson(ByVal LastName As String, ByVal FirstName As String) As Person
Return New Person(LastName, FirstName)
End Function
Public Class Person
Public Sub New()
End Sub
Public Sub New(ByVal LastName As String, ByVal FirstName As String)
_LastName = LastName
_FirstName = FirstName
End Sub
Private _LastName As String
Public Property LastName() As String
Get
Return _LastName
End Get
Set(ByVal value As String)
_LastName = value
End Set
End Property
Private _FirstName As String
Public Property FirstName() As String
Get
Return _FirstName
End Get
Set(ByVal value As String)
_FirstName= value
End Set
End Property
End Class
I can consume it from another ASP.NET Application but the problem is when i try to consume it from Classic ASP through SOAP Client 3.0
<%
Dim Result, oSoapClient
Set oSoapClient = Server.CreateObject("MSSOAP.SoapClient30")
oSoapClient.ClientProperty("ServerHTTPRequest") = True
Call oSoapClient.mssoapinit ("http://MyServer/MyWebService/MyWebService.asmx?WSDL")
Result = oSoapClient.CreatePerson("Sassaroli", "Rinaldo")
Response.Write(Result.LastName)
%>
I get an error:
Microsoft VBScript runtime error '800a01a8'
Object required
at "Response.Write(Result.LastName)" Line.
I can see Result is a string array with no elements
I believe that the root cause of the error is the lack of a Set keyword on the line that invokes the web service method. It should look like:
Set Result = oSoapClient.CreatePerson("Sassaroli", "Rinaldo")
That will get you past your initial problem. After that you'll need to read the result object. Your subsequent line of code:
Response.Write(Result.LastName)
will most likely result in another error. That's because the result you're getting is not really a "Person" object, it's an XML representation of that object. You can verify this with the following code:
<%
Dim Result, oSoapClient
Set oSoapClient = Server.CreateObject("MSSOAP.SoapClient30")
oSoapClient.ClientProperty("ServerHTTPRequest") = True
Call oSoapClient.mssoapinit ("http://MyServer/MyWebService/MyWebService.asmx?WSDL")
Set Result = oSoapClient.CreatePerson("Sassaroli", "Rinaldo")
Response.Write( TypeName( Result ) & "<br/>" & vbCrLf )
Response.Write( Result.item(0).text )
%>
The type that will be shown by the TypeName call will be IXMLDomSelection. You can access nodes for this object through methods and properties that are documented here.
The last line of code will display the value of the LastName property.
Hope this leads you in the correct direction.

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