And maybe a bear or two since we live in Wyoming afterall.
Yesterday I went to Casper to speak on a panel about using the Internet to get across a message at the Wyoming Governor's Council Against Impaired Driving. Prior to this event, the largest crowd I spoke infront of was when I got married. It was a great event though, with people truly interested in how to get their message out more effectively across several media outlets. On the panel with me, were representatives from Radio, Print, TV, and the head of the Wyoming Public Radio Station. Certainly, it was interesting to have a peon like me on a panel of people that represent leaders of these other industries in our state.
Overall, since I enjoy social networking, I liked the opportunity to go and discuss this. Speaking to State Legislators, City Council members, leaders of organizations like MADD was certainly a new and enjoyable experience for me.
Afterwards, I met up with another client in Casper for a CRM application they would like to build. It was an interesting experience. At first their IT department was very stand offish against me, but their concerns were eased once I gave them a little background about myself. In the end, they want us to build something that works similar to M$ CRM that integrates into Outlook, but they don't want to pay the licensing fees to M$. *sigh* I'm more then happy to build them such an application, but I doubt I'll be able to bring it into a budget range that will satisfy them. Anyways, keep an eye out for this in my blog, because if we do move forward, I'm sure I'll be trying new things since this will be a Windows Application, not Web.
Thursday, October 6, 2016
Implementing Google Maps
My project for Pinedale Properties implements Google Maps by showing property locations Below is the source code for how I implemented this solution. This code was done using ASP .NET 2.0.
First we have to insert the Script Source for the Google Map API... Don't forget to use your own key.
Next up we need to modify the body tag to execute the script on load, and to call the GUnload() function on unload.
On the control that displays the google map, I've added the following HTML Field...
Once all of that is finished, it's time to go play in the source code...
In the source, code, I first insert the Javascript code that is always present
This function takes in as parameters, the latitude, longitude, and a number. Latitude and longitude should be standard enough. The number tells the javascript which image to display on the map. (ie #1 for the first listing, #2 for the second, etc.)
Finally, after that code is generated, I add in the finishing touches to the Javascript.
As I move down the road, I see myself updating this feature with some additional features. Such as being able to click on a property in the list and having it highlight the map marker. Below is the finish product.
First we have to insert the Script Source for the Google Map API... Don't forget to use your own key.
<script src="http://maps.google.com/maps?file=api&v=2&key=KEYHERE" type="text/javascript">script
Next up we need to modify the body tag to execute the script on load, and to call the GUnload() function on unload.
<body onload="Page_Load()" onunload="GUnload()">
On the control that displays the google map, I've added the following HTML Field...
<div id="map" style="WIDTH: 350px; HEIGHT: 600px">div>
Once all of that is finished, it's time to go play in the source code...
In the source, code, I first insert the Javascript code that is always present
'MAP HEADER CODE
sbGoogleCode.Append(""text/javascript" & Chr(34) & ">" & vbCrLf)
sbGoogleCode.Append("//' place icon on map
sbGoogleCode.Append("var icon" & num & "= new GIcon();" & vbCrLf)
sbGoogleCode.Append("icon" & num & ".image = " & Chr(34) & "MapIcons/" & num & ".gif" & Chr(34) & ";" & vbCrLf)
sbGoogleCode.Append("icon" & num & ".shadow = " & Chr(34) & "images/shadow.gif" & Chr(34) & ";" & vbCrLf)
sbGoogleCode.Append("icon" & num & ".iconSize = new GSize(47, 53);" & vbCrLf)
sbGoogleCode.Append("icon" & num & ".shadowSize = new GSize(73, 53);" & vbCrLf)
sbGoogleCode.Append("icon" & num & ".iconAnchor = new GPoint(22, 53);" & vbCrLf)
sbGoogleCode.Append("icon" & num & ".infoWindowAnchor = new GPoint(4, 1);" & vbCrLf)
sbGoogleCode.Append("var point" & num & " = new GLatLng(" & lat & ", " & longitude & ");" & vbCrLf)
sbGoogleCode.Append("map.addOverlay(new GMarker(point" & num & ", icon" & num & "));" & vbCrLf)
End If
End Sub
This function takes in as parameters, the latitude, longitude, and a number. Latitude and longitude should be standard enough. The number tells the javascript which image to display on the map. (ie #1 for the first listing, #2 for the second, etc.)
Finally, after that code is generated, I add in the finishing touches to the Javascript.
sbGoogleCode.Append("}" & vbCrLf)Finally after that is completed, add the Javascript code to the page using the ClientScript.RegisterStartupScript function as shown here.
sbGoogleCode.Append("}" & vbCrLf)
sbGoogleCode.Append("//]]>" & vbCrLf)
sbGoogleCode.Append(")
sbGoogleCode.Append("script>")
If (Not Page.ClientScript.IsStartupScriptRegistered("clientScript")) Then
Page.ClientScript.RegisterStartupScript(Me.GetType(), "clientScript", sbGoogleCode.ToString, False)
End If
As I move down the road, I see myself updating this feature with some additional features. Such as being able to click on a property in the list and having it highlight the map marker. Below is the finish product.
Fixing shortcomings in urlRewriter.net
One of my current projects, allows for the customer to create their own pages on the fly. As such, I needed to create a URL Rewriter so that they could create Search Engine friendly URLs. During my hunt I came across URL Rewriter .NET, an open source solution.
The initial problem that I ran into is, that it disables handling of the default page handlers. After following their suggestions and adding the following expression to handle default pages, I realized it didn't handle subdirectories very smoothly.
<rewrite url="^(.*)/(\?.+)?$" to="$1/default.aspx$2" processing="stop">
Basically, http://www.paulnkaty.com/test/ would resolve fine. http://www.paulnkaty.com/test would return a 404 not found error. For now, until I get a chance to look through the source code and find the cause of the problem, I thought I would give you a work around.
<redirect url="(.*)/test$" to="$1/test/" processing="stop">
For this, it looks for the URL to end in the directory name, without a trailing slash. If it matches this case, it redirects the URL to the same location with a trailing slash. Luckily the application uses Regular Expression (RegEx) to parse the URL. Admittedly, this is a weak point for me, so it'll take some time before I can really find a nice solution for this project.
Overall, it's not a terrible solution, but I will probably look down the road at some better ideas. One limitation I do have, is that our primary web server is still on IIS 5.
The initial problem that I ran into is, that it disables handling of the default page handlers. After following their suggestions and adding the following expression to handle default pages, I realized it didn't handle subdirectories very smoothly.
<rewrite url="^(.*)/(\?.+)?$" to="$1/default.aspx$2" processing="stop">
Basically, http://www.paulnkaty.com/test/ would resolve fine. http://www.paulnkaty.com/test would return a 404 not found error. For now, until I get a chance to look through the source code and find the cause of the problem, I thought I would give you a work around.
<redirect url="(.*)/test$" to="$1/test/" processing="stop">
For this, it looks for the URL to end in the directory name, without a trailing slash. If it matches this case, it redirects the URL to the same location with a trailing slash. Luckily the application uses Regular Expression (RegEx) to parse the URL. Admittedly, this is a weak point for me, so it'll take some time before I can really find a nice solution for this project.
Overall, it's not a terrible solution, but I will probably look down the road at some better ideas. One limitation I do have, is that our primary web server is still on IIS 5.
URLRewriting in the land of Global.asax
Earlier I wrote about using URLRewriter.net. It's a decent piece of software, but has some serious drawbacks, especially since it forces you to modify the IIS configuration for a specific website. As a webmaster, trying to keep that straight on 1500+ websites isn't exactly an ideal solution. So today, I'm going to present you with a fairly basic method in this case of handling it in the global.asax file. This method is handled inside the Application_BeginRequest Subroutine.
Here is the RemoveFileExtension function. We can't use the Path.GetFilenamewithoutExtension function because of the potential case for a QueryString at the end of a dynamic page:
Now onto the rest of our application...
In the above code, it is specifically looking for a page named "webpageNN.aspx" where NN is equal to the page ID. So the page would be labeled as webpage18.aspx. It then rewrites the URL to webpage.aspx?pageid=18. The user, searchengines, etc. still see webpage18.aspx though. Easily enough, this could be expanded to be used with more friendly URLs, such as mywedding.aspx which would rewrite to webpage.aspx?pageid=18 via the addition of database information.
Dim incoming As HttpContext = HttpContext.Current
Dim oldpath As String = incoming.Request.Path.ToLower()
Dim pageid As String
Dim DynamicPageName As String
Dim BareName As String
Dim regex As System.Text.RegularExpressions.Regex
Dim matches As MatchCollection
'------------------------------------------------
' URL rewriter for WebPage.aspx?pageid=xxx
'------------------------------------------------
' set unique page name for dynamic pages in web.config
DynamicPageName = ConfigurationManager.AppSettings("cfgWebPageName")
' get the bare name for moving pageid in the string
BareName = RemoveFileExtension(DynamicPageName)
Here is the RemoveFileExtension function. We can't use the Path.GetFilenamewithoutExtension function because of the potential case for a QueryString at the end of a dynamic page:
Function RemoveFileExtension(ByVal parmFileName as String) as String
Dim FullLength as Integer = parmFileName.Length
Dim RightStringToCut as String = parmFileName.Substring(parmFileName.LastIndexOf("."))
Dim RightLength as Integer = RightStringToCut.Length
Dim NewStringLength as Integer = FullLength - RightLength
Dim NewWebPageName as String = parmFileName.Substring(0, NewStringLength)
Return NewWebPageName
End Function
Now onto the rest of our application...
regex = new System.Text.RegularExpressions.Regex(BareName & "(\d+).aspx", RegexOptions.IgnoreCase Or RegexOptions.IgnorePatternWhitespace)
matches = regex.Matches(oldpath)
If matches.Count > 0 Then
pageid = matches(0).Groups(1).ToString()
incoming.RewritePath(DynamicPageName & "?pageid=" + pageid)
Else
incoming.RewritePath(oldpath)
End If
In the above code, it is specifically looking for a page named "webpageNN.aspx" where NN is equal to the page ID. So the page would be labeled as webpage18.aspx. It then rewrites the URL to webpage.aspx?pageid=18. The user, searchengines, etc. still see webpage18.aspx though. Easily enough, this could be expanded to be used with more friendly URLs, such as mywedding.aspx which would rewrite to webpage.aspx?pageid=18 via the addition of database information.
Adding a 3rd party form in Active Admissions
Recently, I was asked by another college how we successfully implemented forms that we want to submit to third parties, such as our Library system's search network, our Google search, etc. So today, I'm going to cover how that is done. This trick is fairly simple, and best implemented within XSLT.
First you'll create your XSLT document with the following shell...
As you can see in the middle, I've highlighted where your form code will eventually go.
Now we'll start creating your form. In this example case, we are going to use a simple Google Search. Below is the Textbox for the search.
This is fairly straight forward... now comes the real fun, the Submit Button.
Hopefully while looking at this you'll notice that instead of actually putting up a quote, in the XSLT, I am actually putting in encoded quotes. This is very important otherwise it won't work.
While I'm on the subject... this would be much more straight forward if Datatel enabled the ability to insert Javascript directly into their Rich Text Editor. Unfortunately they turn that capability off, and the only way to get it switched is via a programmer switch. So I encourage all Active Admissions users to contact Datatel and submit a request to get it turned on. Part of the reason for this is, that I believe schools should have the capability to use all technology, and not be limited. Give us the freedom to create!
Feel free to post, or contact me if you have any questions on this process.
Cya,
Paul
First you'll create your XSLT document with the following shell...
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ACControl="urn:This:Control" xmlns:ACXslt="urn:ActiveCampus:XSLTLibrary" exclude-result-prefixes="ACControl ACXslt">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/">
<!--- Put your Form Here -->
</xsl:template>
</xsl:stylesheet>
As you can see in the middle, I've highlighted where your form code will eventually go.
Now we'll start creating your form. In this example case, we are going to use a simple Google Search. Below is the Textbox for the search.
<input type="text" name="q" />
This is fairly straight forward... now comes the real fun, the Submit Button.
<input type="submit" name="b1" value="Go" onclick="javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("b1", "", false, "", "http://www.google.com/search", false, false))" id="b1" />
Hopefully while looking at this you'll notice that instead of actually putting up a quote, in the XSLT, I am actually putting in encoded quotes. This is very important otherwise it won't work.
While I'm on the subject... this would be much more straight forward if Datatel enabled the ability to insert Javascript directly into their Rich Text Editor. Unfortunately they turn that capability off, and the only way to get it switched is via a programmer switch. So I encourage all Active Admissions users to contact Datatel and submit a request to get it turned on. Part of the reason for this is, that I believe schools should have the capability to use all technology, and not be limited. Give us the freedom to create!
Feel free to post, or contact me if you have any questions on this process.
Cya,
Paul
Install notes for installing ActiveCampus CMS/ActiveAdmissions
Well I got a new toy a couple of weeks ago. My very own development server for making changes to ActiveCampus/ActiveAdmissions without the fear of blowing up our live website. Below are some key notes that will probably help you on your way to installing this software. If you're like us, Datatel came in and did the initial installation. So I never had any experience doing it myself. Kinda scary if we ever had a blow up that required a new installation... So below are some notes that I made.
1. Create the Database and user ahead of time. Initially give the new user global powers, and after you are finished installing, backdown the permissions to the appropriate level.
2. Most importantly. Nowhere in their requirements or documentation does it talk about this... but if you don't install it, the software will never work. You must download and install Microsoft's Web Services Enhancements (WSE) 2.0 AND 3.0 for Microsoft .NET. It took me a good 2 or 3 hours to track down the solution. So hopefully this saves somebody that amount of time.
Outside of that the install went fairly smoothly. It requires quite a bit of hands on work, because their installer is not setup to configure the log directories or modify folder permissions. But after you that up and running, things should smooth out for you.
So now that I have my test install up and running... hopefully I'll be posting more tricks and tips from working on my development environment.
For those keeping track at home.. my test server is a Dell Poweredge with Dual Quad-Core processors, 12GB of memory, and 2 Raid-1 Drives. Way overkill for a dev server, but I'm happy. :)
1. Create the Database and user ahead of time. Initially give the new user global powers, and after you are finished installing, backdown the permissions to the appropriate level.
2. Most importantly. Nowhere in their requirements or documentation does it talk about this... but if you don't install it, the software will never work. You must download and install Microsoft's Web Services Enhancements (WSE) 2.0 AND 3.0 for Microsoft .NET. It took me a good 2 or 3 hours to track down the solution. So hopefully this saves somebody that amount of time.
Outside of that the install went fairly smoothly. It requires quite a bit of hands on work, because their installer is not setup to configure the log directories or modify folder permissions. But after you that up and running, things should smooth out for you.
So now that I have my test install up and running... hopefully I'll be posting more tricks and tips from working on my development environment.
For those keeping track at home.. my test server is a Dell Poweredge with Dual Quad-Core processors, 12GB of memory, and 2 Raid-1 Drives. Way overkill for a dev server, but I'm happy. :)
Monday, September 19, 2011
Permanent Redirects in ActiveCampus CMS
I recently received a request on how to handle Permanent Redirects (301 Redirects) in Datatel's Active Campus... So without further ado, here is my solution to that problem.
First thing I did was create a new Template, in my case titled Template404.aspx. Be sure to include any .NET Controls specific to your implementation...
Now you should be able to create a page with this template. It is not necessary to enter the template designer. Just make sure the page is published. Make sure the page loads up in your browser by pointing directly to it.
This next part, will cause a short pause and delay, so I recommend that you do it during non-peak hours. Also, create a backup of your web.config file before making any changes.
On the public website instance, open the web.config file. And search for <customerrors. Assuming you have not modified it at all, you can change it to:
That should do it.
Hopefully this helps you out down the road!
Paul
First thing I did was create a new Template, in my case titled Template404.aspx. Be sure to include any .NET Controls specific to your implementation...
<%@ OutputCache NoStore="true" Duration="1" VaryByParam="none" %>Next, I needed to create the .NET control that actually handles all of my redirects. Now mind, you my method is to have all redirects in a central location. This is also useful for those short hand URL's that you want to go somewhere deep into the site. Like perhaps, www.cwc.edu/library will actually take you to www.cwc.edu/resources/library. This way our library, has a short link they can advertise on their materials. Also, much easier for users to remember the shorter version, then trying to remember to add in resources. So for my example, I'm going to handle some Library Page redirections we used. To add additional, pages, you simply add additional case statements. Additionally, the last part of this script, also takes care of the case when somebody enters cwc.edu (I then want to push them automatically to the www.).
<%@ Page Language="C#" AutoEventWireup="true" Inherits="ActiveCampus.Websites.Controls.CMSPage" StyleSheets="/Website Resources/css/SiteStyle.css:all|/Website Resources/css/SiteStylePrint.css:print" Async="true" %>
<%@ Register Src="/Templates/controls/404control.ascx" tagName="control404" TagPrefix="control404" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head id="Head1" runat="server">
<title>Central Wyoming College - Page Not Found Error</title>
<script language="javascript" src="/Media/Website%20Resources/scripts/mootools.js" type="text/javascript"></script>
<script language="javascript" src="/Media/Website%20Resources/scripts/AC-Core.js" type="text/javascript"></script>
<script language="javascript" src="/Media/Website%20Resources/scripts/AC-LightBox.js" type="text/javascript"></script>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<!--[if lte IE 6]>
<link rel="stylesheet" type="text/css" href="/Media/Website%20Resources/css/SiteStyleIE6.css" />
<![endif]-->
<link rel="icon" type="image/vnd.microsoft.icon" href="/Media/Website Resources/Favicon.ico" />
</head>
<body id="body" runat="server">
<div id="pageCt" class="search">
<form id="form1" action="/" runat="server">
<div id="pageCtInner">
<div id="pageCtBG">
<div id="zoneCt">
<div id="gridCt">
<div id="zone2">
<div id="centerContent">
<control404:control404 id="control404" runat="server" />
</div>
</div>
<div id="zone1">
</div>
<div class="spacer"> </div>
</div>
<div class="spacer"> </div>
</div>
<div class="spacer"> </div>
</div>
<div class="spacer"> </div>
<div class="spacer"> </div>
</div>
<div class="spacer"> </div>
</form>
</div>
</body>
</html>
<%@ Language=VBScript %>Next you'll add this template to the Website Workflow. You do that by going to Website, Right clicking the top "Website" folder and selecting Workflow Properties. Click the Template Groups Tab then select your template bundle. Now click the Templates tab in the bottom section. Goto the bottom, and click the add button to add your template. Click Ok, and exit the workflow.
<%
' Permanent redirection
Dim str = Request.RawUrl.Replace("/404error.aspx?404;http://www.cwc.edu:80","")
str = str.Replace("/404error.aspx?404;http://cwc.edu:80","")
str = str.tolower
If Request.QueryString("aspxerrorpath") <> String.Empty Then
str = Request.QueryString("aspxerrorpath").tolower
End If
'Handle Academic Program URLs
If str.indexOf("/academics/programs-of-study/") >=0 or str.indexOf("/Academics/Programs-of-Study/") >=0 Then
Response.Status = "301 Moved Permanently"
Response.AddHeader ("Location", "http://www.cwc.edu/academics/programs/")
else
Select Case str.tolower
Case "/resouces/library/testingcenter/testcenterrec.aspx"
Response.Status = "301 Moved Permanently"
Response.AddHeader("Location","http://www.cwc.edu/resources/Library/testingcenter/testcenterrec.html")
Case "/resources/library/testingcenter/fees.aspx"
Response.Status = "301 Moved Permanently"
Response.AddHeader("Location","http://www.cwc.edu/resources/Library/testingcenter/Fees.htm")
Case "/resources/library/testingcenter/clep.aspx"
Response.Status = "301 Moved Permanently"
Response.AddHeader("Location","http://www.cwc.edu/resources/Library/testingcenter/Clep.htm")
Case "/resources/library/testingcenter/default.aspx"
Response.Status = "301 Moved Permanently"
Response.AddHeader("Location","http://www.cwc.edu/resources/Library/testingcenter/default.htm")
Case "/resources/library/librarydistance.aspx"
Response.Status = "301 Moved Permanently"
Response.AddHeader("Location","http://www.cwc.edu/resources/Library/librarydistance.htm")
Case Else
Response.write ("<p>Oops... This page can't be found. Please visit the <a href='http://www.cwc.edu/azindex.aspx'>Site Map</a> for a listing of pages.<br />Error Page: " & str & "<br />Also try search at the top of the website to find the page you are looking for.")
Dim strRootURL = Request.URL.ToString.Replace("http://cwc.edu/Cache/Templates/Template404.aspx?=404;","")
'Response.write("<p>URL: " & strRootURL)
if strRootURL.startswith("http://cwc.edu") Then
strRootURL = strRootURL.Replace("http://cwc.edu","http://www.cwc.edu")
Response.Redirect(strRootURL)
End If
End Select
End If
Response.End
%>
Now you should be able to create a page with this template. It is not necessary to enter the template designer. Just make sure the page is published. Make sure the page loads up in your browser by pointing directly to it.
This next part, will cause a short pause and delay, so I recommend that you do it during non-peak hours. Also, create a backup of your web.config file before making any changes.
On the public website instance, open the web.config file. And search for <customerrors. Assuming you have not modified it at all, you can change it to:
<customErrors mode="On" defaultRedirect="ErrorPages/ErrorPage.aspx" />Modify the defaultRedirect location to be the location of your error. In our case, we want users to always just think it is a page not found error, even if there is a programming error in a form. But you can also modify it to handle just 404 error types.
That should do it.
Hopefully this helps you out down the road!
Paul
Labels:
Active Admissions,
Active Campus,
Web Development
Subscribe to:
Posts (Atom)