M.Efe Ozer’s Weblog

June 27, 2009

CascadingDropDown ( AjaxControlToolkit ) and PageMethods

Filed under: Asp.Net, Notes to Myself — Tags: , — Mehmet Efe Ozer @ 2:48 pm

 

When i looked cascading dropdowns of AjaxControlToolkit at first i confused so i gave up and wrote my own client scripts. But i found a very easy example in my code sample archive, so here it is.

What i need is 2 pagemethod for populate dropdown items and 1 ( or 2 ) for get values from them. Values in dropdownlists are type of “CascadingDropDownNameValue” . It needs name and value.

In client side scriptmanager “EnablePageMethods” attribute should set true. Extender codes are below :

<ajaxToolkit:CascadingDropDown runat="server" ID="cdd1"
TargetControlID="ddl1" PromptText="Select Type" Category="type" LoadingText="[Loading]"
   
ServiceMethod="GetType" />
<
ajaxToolkit:CascadingDropDown runat="server" ID="cdd2"
TargetControlID="ddl2" ParentControlID="ddl1"
   
PromptText="Select Content" Category="content"
   
LoadingText="[Loading]" ServiceMethod="GetContent" />

start

Attributes are describe themselves. So there are two dropdownlist (ddl1,ddl2) and two PageMethods (“GetType”,”GetContent”) needed.

My aim is populate BlogengineNet’s categories or posts in sub dropdownlist. “CascadingDropDownNameValue[]” is need to returned.

using System.Web.Services; using AjaxControlToolkit;

 

[WebMethod]
    [System.Web.Script.Services.ScriptMethod]
    public staticCascadingDropDownNameValue[]
           GetType(stringknownCategoryValues, stringcategory)
    {
            return new[] {
        newCascadingDropDownNameValue("category", "category"),
        newCascadingDropDownNameValue("post", "post") };
      }

    [WebMethod]
    [System.Web.Script.Services.ScriptMethod]
    public staticCascadingDropDownNameValue[]
           GetContent(stringknownCategoryValues, stringcategory)
    {
            if(knownCategoryValues.Contains("category"))
            {
                return(BlogEngine.Core.Category.Categories
                      .Select(c =>
                          newCascadingDropDownNameValue
                        
{ value = c.Id.ToString(), name = c.Title }).ToArray());

            }
            else if(knownCategoryValues.Contains("post"))
            {
                return(BlogEngine.Core.Post.Posts
                      .Select(c =>
                          newCascadingDropDownNameValue
                        
{ value = c.Id.ToString(), name = c.Title }).ToArray());
            }
    }

How values populated are below.

ddl1

ddl2

 

Finally, how are we going to take values? I used a client script which communicate with another pagemethod. In client side, dropdowns “onchange” event:

<asp:DropDownList runat="server" ID="ddl1"
                            onchange="GetSubDDLContent(this.options[this.selectedIndex].value
                            ,this.options[this.selectedIndex].text,'1')"
                                Width="200" />

<asp:DropDownList runat="server" ID="ddl2"
onchange="GetSubDDLContent(this.options[this.selectedIndex].value
,this.options[this.selectedIndex].text,'2')"
    Width="200" />

GetSubDDLContent takes 3 params (third one is non smart identifier for which dropdown sent to value).

Client side:

<scripttype="text/javascript">

     
       function
GetSubDDLContent(id, title, controlid) {

           var param = newArray();

           param[0] = id;

           param[1] = title;

           param[2] = controlid;

           PageMethods.GetSubDDLContent(param,

     OnSubRequestComplete, OnError);

       }

       function OnSubRequestComplete(result) {

//do something

       }

       function OnError(result) {

    //do something      
       }

         
   </script>

On Server Side GetSubDDLContent pagemethod: ( return type is not important )

[WebMethod()]
    [System.Web.Script.Services.ScriptMethod()]
    public static Boolean GetSubDDLContent(IList values)
    {
        if (values[2].ToString() == "1")
        {
          //first dropdown sent 
        }
        else if (values[2].ToString() == "2")
        {
          //second dropdown sent
        }
        return true;
    }
At the end cascadingdropdowns work with pagemethods…

June 4, 2009

BlogEngine Main Menu Extension (just a post, nothing for download)

Filed under: Asp.Net, BlogEngineNet, Notes to Myself — Tags: , , , — Mehmet Efe Ozer @ 1:02 am

 

NavLinkExtension

Admin page of DnANavBar Extension

It was an requirement for who wants to change main menu items and its orders of website from admin panel.

I may publish it, but it is using AjaxControlToolKit and .Net 3.5, so not for now.

I was not so happy with ReorderList control of AjaxCT. When items reordered, update method triggered without  problem, but when update fields with its edit item template, i couldn’t reach the data of item except than index field. In articles people talk about parameters must match in select and update methods. Anyway, i did my updates in OnItemCommand event.

I am thinking about to look JQuery’s drag and drop features next…

May 6, 2009

PrettyPhoto Extension For BlogEngine.Net

Filed under: Asp.Net, BlogEngineNet — Tags: , , , — Mehmet Efe Ozer @ 11:18 pm

 

I was using Lightbox2 for displaying pictures of posts in a BlogengineNet based website InAEA , but with jquery implementation plans, i decided to use jquery all over the website and found similar Lightbox2 script : PrettyPhoto .

I made little changes on Lightbox2 extension and done. My client websites low traffic and it works well for now. But some code parts can better, for example “Item_Serving” function. I don’t know could cause performance problem or not.

 

prettyphoto

 

Some Notes:

  • This extension works with PrettyPhoto Version 2.2.7
  • JQuery required. “jquery-1.3.2.min.js” which i used jquery script, (but i didnt add with this extension, you can find an another extension about add jquery to blogengine, don’t want to my own extension before try with another jquery applications.)
  • Placed prettyphoto.cs to “app_code/extensions” and “prettyphoto” folder to root. ( wrote in readme.txt )
  • I just hardcode default path for folder as;

private const string defaultPath = "prettyPhoto";

  • prettyPhoto.css is not gzipped.
  • Please look PrettyPhoto website to how to use,

actually easy that you need to add rel tag to images like

for single photos => rel=”prettyphoto”

for photos as gallery  => rel=”prettyphoto[ galleryname ]” (without spaces)

DOWNLOAD prettyPhotoExtension

Please write comment for any problem or suggestions…

April 9, 2009

Linq and Group By Multiple Columns

Filed under: .Net, C#, Notes to Myself — Tags: , — Mehmet Efe Ozer @ 2:08 pm

 

It is typical master detail group by query.

We have data as List<T> which it contains master and detail columns (“SentData” in query).

Our master and detail classes:

public class Master
    {
        public string MasterID { get; set; }
        public string MasterDisplayValue{ get; set; }
        public List<Detail> Details { get; set; }
    }

public class Detail
    {
        public string Detail1 { get; set; }
        public string Detail2 { get; set; }
        public string Detail3 { get; set; }
    }

We want to show user’s albums like in this page: InAEA User Albums.

We define columns for grouping with anonymous type;

var result = SentData.GroupBy(g=>
                new {OwnerID=g.AlbumOwner,OwnerDisplay=g.AlbumOwnerDisplayName })
                .Select(resultgroup =>
                    new Master
                               {
                                   MasterID = resultgroup.Key.OwnerID
                                   ,MasterDisplayValue = resultgroup.Key.OwnerDisplay
                                   ,Details = (resultgroup.Select(d => new Detail
                                   {
                                        Detail1 = d.Caption
                                       ,Detail2 = d.Description
                                       ,Detail3 = d.Count.ToString()
                                   }).ToList())
                               }).ToList();

 

 

April 1, 2009

Asp.Net CacheDependency and its Callbacks

Filed under: Asp.Net, C# — Tags: , , , — Mehmet Efe Ozer @ 11:14 pm

 

I am working on a little bit complicated work to reach some information from Second Life.  I need to use a library to do my requests, process them with my classes and need to present on an asp.net website. I will write something about it later.

Just before presentation layer, last callback needed for informed all requested data saved on a xml file. So find a way to track this file is one of the way to handle this problem.

So i decided use cache dependency and CacheItemRemovedCallback.

With cache dependency you create a dependency on a file, on a folder or cached item or items. When your item or items is changed, your dependent item removed from cache.

And it provides two callback that you can catch your item before removed ( CacheItemUpdateCallback ) or after removed( CacheItemRemovedCallback ) from cache.

An important point that these callbacks work with first change on tracked item.So you need to finish your own jobs on your file before creating dependency.  But it gives some options like start to track after definite time past. You need to take a look its overloads.

In my scenario after i reached my data i save it as xml file. File needs to be there so i will create if not. I send a key value pair that i can use in callback for example to understand what is changed in my data file and what was my datafilepath. Xml file creation part is depends on your needs, i just add a root node and an attribute. 20 minute set here for expiration.

private void SetDependency(stringdatafilepath)
    {
       
        XDocument dataxml = newXDocument();
        if(!System.IO.File.Exists(datafilepath))
        {
            dataxml.Declaration
                = newXDeclaration("1.0", "utf-8", "");
            dataxml.Add(newXElement("rootnode"
              
, newXAttribute("rootnodeattr"
                  
, DateTime.Now.ToString())));
            dataxml.Save(datafilepath);
        }
        else
      
{
            dataxml= XDocument.Load(datafilepath);
        }
        CacheDependency dep = newCacheDependency(datafilepath);
        Cache.Insert("keyforitem"
          
, new KeyValuePair<string, XDocument>(datafilepath, dataxml)
            , dep
            , DateTime.Now.AddMinutes(20)
            , TimeSpan.Zero
            , CacheItemPriority.High
            , newCacheItemRemovedCallback(ItemRemovedCallback));
    }

Cachedependency item put in cache with key “keyforitem”, set its value as an keyvaluepair, set 20 mins expiration time. I didn’t try other priority options like “noremove” or else here. (When server resources full server removed items from cache with theirs priority orders.) And finally we assign ItemRemovedCallback.

In my sample i don’t need to use CacheItemUpdateCallback.

Here is CacheItemRemovedCallback

private void ItemRemovedCallback(string key
        , object prevalue, CacheItemRemovedReason reason)
    {
        switch (reason)
        {
            case CacheItemRemovedReason.DependencyChanged:
                {
//my jobs here
                  break;
                }
        }
    }

Dependency Item could be removed from cache by different reasons. Cache priority can be an answer if item removed by memory problems. This sample works on low traffic website so i didn’t faced with problems, also only person is me who change file here.

At the end, if reason is dependencychanged means in this conditions process works ok.

March 10, 2009

Create Data File for SlideShow2 From Picasa Web Albums

Filed under: .Net, BlogEngineNet, Code Stuff — Tags: , , , , , — Mehmet Efe Ozer @ 6:56 pm

Example is here Sandrine Han’s Artworks

I was using SlideShow extension of Danny Douglas. I installed, changed it into xml data provider and used with local photo files.  But after start to thinking about membership system, necessity occurred  uploading and crud operations on albums. Even i coded some management features for local data and photo files. But storage of files,web traffic and one developer dependant management system were other issues that make me stop. So first i start to use Flickr Api. It gives options what i want to do, but for current project i start to work on Picasa Web Albums Data API.

For BlogEngine application that i modified i tried first Rtur.Net’s Picasa Extension.

When you login with your email as in extension’s admin panel you are authenticate to do CRUD options on your albums. But also i was looking for something without login (so no CRUD ) and show it in SlideShow2 which also support Flickr and xml data files.

I like SlideShow2 because customization is so easy in its project structure.

I saw some works for Picasa data provider on project discussions. But this time for some reasons i want to use XML data file for show photos.

So long story short what i did is below. It is based on read Picasa feeds with Google.GData methods and create a xml file with XLinq. I didn’t filter any album or photo, but you can do with using  XLinq.

We need Google.GData.Apps, Google.GData.Client, Google.GData.Extensions, Google.GData.Photos

from here : http://code.google.com/p/google-gdata/downloads/list

Public Shared Sub CreatePicasaSlideShowData()

        Dim service As PicasaService = New PicasaService("myapplicationname")

        dim PicasaUserID as string = "mypicasauserid"

        Dim query As AlbumQuery = New AlbumQuery(PicasaQuery.CreatePicasaUri(PicasaUserID))
        Dim albumfeed As PicasaFeed = service.Query(query)

        Dim xdoc As New XDocument

        xdoc.Declaration = New XDeclaration("1.0", "utf-8", "")
        xdoc.Add(<data startalbumindex="0" transition="CrossFadeTransition"></data>)

        xdoc.Element("data").Add(From albumentry In albumfeed.Entries _
         Let albumAccessor As AlbumAccessor = New AlbumAccessor(CType(albumentry, PicasaEntry)) _
         Let photoquery As PhotoQuery = New PhotoQuery(PicasaQuery.CreatePicasaUri(PicasaUserID, albumAccessor.Id)) _
         Let photofeed As PicasaFeed = service.Query(photoquery) _
             Select New XElement("album" _
                , New XAttribute("title", albumAccessor.AlbumTitle) _
                , New XAttribute("description", albumAccessor.AlbumSummary) _
                , New XAttribute("source", CType(albumentry, PicasaEntry).Media.Thumbnails(0).Attributes("url")) _
                , New XAttribute("transition", "CrossFadeTransition") _
                    , From photoentry In photofeed.Entries _
           Let photoAccessor As PhotoAccessor = New PhotoAccessor(CType(photoentry, PicasaEntry)) _
                        Let photoe As PicasaEntry = CType(photoentry, PicasaEntry) _
                    Select New XElement("slide" _
                        , New XAttribute("title", photoAccessor.PhotoTitle) _
                        , New XAttribute("description", photoAccessor.PhotoSummary) _
                        , New XAttribute("source", photoe.Content.AbsoluteUri) _
                      , New XAttribute("thumbnail", photoe.Media.Thumbnails(1).Attributes("url")) _
                      , New XAttribute("link", String.Empty) _
                      , New XAttribute("datetaken", photoe.Updated.ToShortDateString))))

        xdoc.Save("mydata.xml")
End Sub


You can change thumbnail formats, add “link” for pictures ( i left empty), and find a sensible date field from feed for “datetaken” field or change transition type.

Example is here Sandrine Han’s Artworks

 

February 27, 2009

GateKeeper on BlogEngineNet

Filed under: Asp.Net, BlogEngineNet — Tags: , , — Mehmet Efe Ozer @ 5:37 am

I was complaining about spiders and crawler entries on my visitor map. It is not only matter of visitor accuracy but also they using traffic. I wrote a http module for blocking some ip numbers which tried my registration page also. But all my works about unwanted visitors were lack of management.

Now I am using GateKeeper of Chris Blankenship and it is working good for me. Has easy implementation and very good admin panel. When i checked honeypot violation’s ip numbers, i found diffrent spider locations than i’ve already know before.

I allowed some known user agents. They are storing in a xml file, so i still could prevent their entires from my visitor map. I added a little extra check to my codes like this :

Add a function to my visitor tracking class that returns ip number is known spider or not:

Public Shared Function IsAllowedSpider(ByVal ip As String) As Boolean

        Return XDocument.Load(AllowedSpiderListDataFilePath) _
        .Descendants.Elements("ipaddress").Elements("entry") _
        .Where(Function(f) f.Attribute("ipaddress").Value = ip).Count > 0

        Return False
End Function

I still suspicious about visitors from some cities but i eliminated a lot.  By the way map is here (little patience for loading map :) ).

February 3, 2009

Last Works

Filed under: .Net, Asp.Net, BlogEngineNet, C#, Notes to Myself — Tags: , , , , — Mehmet Efe Ozer @ 10:18 pm

 

Status: Demonstation only, in progress, not documented

  • Web Site Visitors on Virtual Earth Map and show with Ajax Collapsible Panel

http://www.inaea.org/other/visitorcities.aspx  (implemantation with XML data file of this article )

Old version is here : http://www.inaea.org/other/visitorcitymap.aspx

  • Web Site Visitors on Virtual Earth Map and show in AGDataGrid of DevExpress

http://www.inaea.org/other/silverlightvisitorcitymap.aspx

Used technologies : Silverlight,AGDataGrid,WCF,Aspx(C#) ,Virtual Earth

  • Show Second Life Visitors on Website in AGDataGrid of DevExpress

http://www.inaea.org/other/silverlightslvisitors.aspx

http://www.inaea.org/other/slvisitors.aspx (no silverlight version)

Used technologies : Silverlight,AGDataGrid,WCF,Aspx(C#),Linden Scripting Language with aspx integration

December 13, 2008

Simple Works on GeoRSS with XLinq

Filed under: .Net, Code Stuff, Notes to Myself — Tags: , , — Mehmet Efe Ozer @ 2:54 pm

Note to myself

What is written here is not optimized and not ensure security

This is what i did for my visitor map georss format xml file.

a sample node of my georss:

<?xml version=”1.0″ encoding=”utf-8″?>
<rss xmlns:geo=”http://www.w3.org/2003/01/geo/wgs84_pos#”>
<channel>
<title>Locations</title>
<link></link>
<item>
<title>Hudson, OH UNITED STATES</title>
<city>Hudson</city>
<country>UNITED STATES</country>
<description>10 Visits</description>
<geo:long>-81.4512</geo:long>
<geo:lat>41.2447</geo:lat>
<visitorcount>10</visitorcount>
</item>

</channel>
</rss>

usings:

Imports System.Collections
Imports System.Linq
Imports System.Xml.Linq
'we need it for using :<geo:long></geo:long> <geo:lat></geo:lat> 
Imports <xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">
'where is my xml file
    Public Shared VisitorDataPathURL As String
'class that store some info
    Public Class UserIpInfo

        Public Property IPAddress() As String...End Property
        Public Property Location() As String...End Property
        Public Property Longitude() As Double...End Property
        Public Property Latitude() As Double...End Property
        Public Property Country() As String...End Property
        Public Property City() As String...End Property
'constructors
        Public Sub New(ByVal iPAddress As String, _
                       ByVal location As String, _
                       ByVal cityname As String, _
                       ByVal countryname As String, _
                       ByVal lon As Double, _
                       ByVal lat As Double
...
        End Sub

        Public Sub New()
        End Sub

    End Class

we provide some info from our application and here are methods :

Public Shared Sub DoVisitorWork(ByVal uinfo As UserIpInfo)
'look for city if already exists
            Dim xdoc As XDocument = XDocument.Load(VisitorDataPathURL)
           Dim searched As XElement = (From xel As XElement In xdoc.Descendants.Elements("item") _
                                  Where xel.Element("city").Value.ToString.Trim.ToLowerInvariant _
                                    = uinfo.City.Trim.ToLowerInvariant _
                                     Select xel).FirstOrDefault
'if city is new , new xelement creating by vb.net xml literal
            If searched Is Nothing Then
                searched = _
                <item>
                    <title><%= uinfo.Location %></title>
                    <description><%= uinfo.Location %></description>
                    <city><%= uinfo.City %></city>
                    <country><%= uinfo.Country %></country>
                    <geo:long><%= uinfo.Longitude %></geo:long>
                    <geo:lat><%= uinfo.Latitude %></geo:lat>
                    <visitorcount>1</visitorcount>
                </item>

‘other methods to create xelement :

                'Dim myxml As String = "<item>" & System.Environment.NewLine & _
                '"<title><%= uinfo.Location %></title>" & System.Environment.NewLine _
        '    & " <description>" & uinfo.Location & "</description>" & System.Environment.NewLine _
                '    & "<city>" & uinfo.City & "</city>" & System.Environment.NewLine _
                '    & "<country>" & uinfo.Country & "</country>" & System.Environment.NewLine _
             '    & "<geo:long>" & uinfo.Longitude & "</geo:long>" & System.Environment.NewLine _
                '    & "<geo:lat>" & uinfo.Latitude & "</geo:lat>" & System.Environment.NewLine _
                '    & "<visitorcount>1</visitorcount></item>"
                'searched = XElement.Parse(myxml)

                'searched = New XElement("item")
                'searched.Add(New XElement("title", uinfo.Location))
                'searched.Add(New XElement("description", uinfo.Location))
                'searched.Add(New XElement("city", uinfo.Location))
                'searched.Add(New XElement("country", uinfo.Location))
                'searched.Add(New XElement("geo:long", uinfo.Longitude))
                'searched.Add(New XElement("geo:lat", uinfo.Latitude))
                'searched.Add(New XElement("visitorcount", 1))

              

‘add our new city

                xdoc.Element("rss").Element("channel").Add(searched)
            Else

‘if city is already exists we add 1 more to visitor count

                searched.Element("visitorcount").Value = _
                (CType(searched.Element("visitorcount").Value.Trim _
                                                          , Int64) + 1).ToString
        searched.Element("description").Value = searched.Element("visitorcount").Value & " Visits"
            End If

’save document

            xdoc.Save(VisitorDataPathURL)
    End Sub

show records on gridview,return value can be diffrent than ilist

  Public Shared Function GetVisitorList() As IList

        Dim MyList = (From ui As XElement _
                      In XDocument.Load(VisitorDataPathURL).Descendants.Elements("item") _
                       Order By ui.Element("country").Value _
                      Select Place = ui.Element("title").Value _
                        , City = ui.Element("city").Value _
                        , Country = ui.Element("country").Value _
                        , Count = CInt(ui.Element("visitorcount").Value)).ToList
'got visitorcount property, will be shown in footer of gridview
        VisitorCount = MyList.Select(Function(count) count.Count).Sum

        Return MyList
    End Function
    Public Shared Property VisitorCount() As Integer...End Property

All this stuff in a class…

In virtual earth show this file with VEDataType.GeoRSS method.  Here is EXAMPLE PAGE

In the future clustured pushpins and rich content pushpin descriptions will be there…

My Visitor Map Example Using Virtual Earth and MaxMind’s GeoIP API

Filed under: Asp.Net, BlogEngineNet, C#, Notes to Myself — Tags: , , , , — Mehmet Efe Ozer @ 12:29 am

notes to myself

I try to do my own visitors locations application on a BlogEngine.NET base website Inaea*.

It is still in progress and needs long way to go. You can take a look from here.

What i need

  • A HTTP Module for tracking visitors

It is just an implementation of what Mad Kristensen explain. Simply for reusing your codes is enough reason of using

http module instead of global asax.

First we need to put our file on App_Code folder and we need to register it to webconfig.

How to register to webconfig : (For iis7 platform logic is same)

<httpModules>
...
            <add name="VisitorLog" type="VisitorLog"/>
...
</httpModules>
I am using their GeoLite City bin format database. Mostly going good for me, 
I just got some visitors in ocean and North Pole :) 
How to use :
  //make a call to hostip handler to get ip info 

           LookupService ls = new LookupService
               (context.Server.MapPath("mydatalocation"), LookupService.GEOIP_STANDARD);
           //get city location of the ip address
           Location l = ls.getLocation("visitorIpAddress");
           if (l != null)
           {

              do my work with => l.city , l.countryCode, l.city,
 l.countryName, l.longitude, l.latitude
           }
           else
           {
               //my b plan
           }

       }
  • Virtual Earth Map

I use GeoRSS format  for data .(VEDataType.GeoRSS) Because of incomplete works, i planned to write details of map codes later times. I need to eliminate spiders, session handles needs some work, better gridview for show data etc… But as i said before it is just a test and still in progress.

a sample node of georss:

<?xml version=”1.0″ encoding=”utf-8″?>
<rss xmlns:geo=”http://www.w3.org/2003/01/geo/wgs84_pos#”>
<channel>
<title>Locations</title>
<link></link>
<item>
<title>Hudson, OH UNITED STATES</title>
<city>Hudson</city>
<country>UNITED STATES</country>
<description>10 Visits</description>
<geo:long>-81.4512</geo:long>
<geo:lat>41.2447</geo:lat>
<visitorcount>10</visitorcount>
</item>

</channel>
</rss>

*InAEA

InAEA—International Art Education Association is an online group located in the virtual world of Second Life for all art educators around the world to communicate. InAEA in Second Life not only have a meeting place, but also have a free gallery and avatars for all art educators to use!…

Older Posts »

Blog at WordPress.com.