ASP.NET 开发 WAP 网站

随着手机上网的兴起,我们实际项目中可能会碰到专门针对手机开发的网站,虽然asp.net 也有专门的wap控件库,但在某些时候,这也不是完美的解决方案。asp.net webfrom具有高效开发网站的优势,但对于手机上网来说,viewstate确实是个大麻烦。本文根据自己的一些开发经验而来,也算是对项目的一个总结吧。

  虽然是基于asp.net webforms,但我并没有使用webfrom的任何控件,开发方式有点像asp或者jsp,但这也是为了避免产生任何viewstate而作的一个折中。就目前来说,wap网站的界面都还相对简单,大多以超链接为主,当然也可少许按钮,但以此方法都可以处理简单的逻辑。

  为了不产生viewstate,我们去掉了aspx页面中的<form runat="server"></form>标签,但在输出内容的格式,排版等,就要自己手动控制了。

  如下代码所示:

 

ASP.NET WebForm开发WAP网站 - adyhpq - adyhpq的个人主页 代码
    
      
< table cellpadding = " 3 " cellspacing = " 0 " >
<%
list
< student > slist = student.createpersons();
if (slist != null && slist.count > 0 )
{
stringbuilder sb
= new stringbuilder();
foreach (student item in slist)
{
sb.append(
" <tr><td><a href=\ " .. / detail.aspx ? id = " );
sb.append(item.studentid);
sb.append(
" \ " > " );
sb.append(item.studentid);
sb.append(
" </a></td><td> " );
sb.append(item.name);
sb.append(
" </td><td> " );
sb.append(item.major);
sb.append(
" </td></tr> " );
}

response.write(sb.tostring());
}
%>
</ table >

 

 

运行后,查看页面的html源代码,我们就会看到清洁的页面内容,如下图所示:

 

   ASP.NET WebForm开发WAP网站 - adyhpq - adyhpq的个人主页

  有爱好研究的同学,请下载demo查看具体。如有不足之处,还请指正。

  demo下载地址

使用ASP.NET开发WAP很简单,只需要新建一个空的网站,向其中添加移动WEB窗体即可.可以使用OPERA浏览器与M3GATE来调试网页,

强制输出WML,可以在WEB.CONFIG中 <system.web>下添加以下内容:

< browserCaps >
            
< result  type ="System.Web.Mobile.MobileCapabilities, System.Web.Mobile, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
            
< use  var ="HTTP_USER_AGENT" />
                    preferredRenderingType = "wml11"
                    preferredRenderingMime = "text/vnd.wap.wml"
                    preferredImageMime = "image/vnd.wap.wbmp"
</ browserCaps >  

 

如果需要其它相关属性可以完整的添加设置属性:

 

< browserCaps >
            
< result  type ="System.Web.Mobile.MobileCapabilities, System.Web.Mobile, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
            
< use  var ="HTTP_USER_AGENT" />
            browser=Unknown
            version=0.0
            majorversion=0
            minorversion=0
            frames=false
            tables=false
            cookies=false
            backgroundsounds=false
            vbscript=false
            javascript=false
            javaapplets=false
            activexcontrols=false
            win16=false
            win32=false
            beta=false
            ak=false
            sk=false
            aol=false
            crawler=false
            cdf=false
            gold=false
            authenticodeupdate=false
            tagwriter=System.Web.UI.Html32TextWriter
            ecmascriptversion=0.0
            msdomversion=0.0
            w3cdomversion=0.0
            platform=Unknown
            css1=false
            css2=false
            xml=false
            mobileDeviceManufacturer = "Unknown"
            mobileDeviceModel = "Unknown"
            gatewayVersion = "None"
            gatewayMajorVersion = "0"
            gatewayMinorVersion = "0"
            preferredRenderingType = "wml11"
            preferredRenderingMime = "text/vnd.wap.wml"
            preferredImageMime = "image/vnd.wap.wbmp"
            defaultScreenCharactersWidth = "12"
            defaultScreenCharactersHeight = "6"
            defaultScreenPixelsWidth = "96"
            defaultScreenPixelsHeight = "72"
            defaultCharacterWidth = "8"
            defaultCharacterHeight = "12"
            screenBitDepth = "1"
            isColor = "false"
            inputType = "telephoneKeypad"
            numberOfSoftkeys = "0"
            maximumSoftkeyLabelLength = "5"
            canInitiateVoiceCall = "false"
            canSendMail = "true"
            hasBackButton = "true"
            rendersWmlDoAcceptsInline = "true"
            rendersWmlSelectsAsMenuCards = "true"
            rendersBreaksAfterWmlAnchor = "false"
            rendersBreaksAfterWmlInput = "false"
            rendersBreakBeforeWmlSelectAndInput = "true"
            requiresAttributeColonSubstitution = "true"
            requiresPhoneNumbersAsPlainText = "false"
            requiresUrlEncodedPostfieldValues = "false"
            requiredMetaTagNameValue = ""
            rendersBreaksAfterHtmlLists = "true"
            requiresUniqueHtmlCheckboxNames = "true"
            requiresUniqueHtmlInputNames = "true"
            requiresUniqueFilePathSuffix = "true"
            supportsCss = "false"
            hidesRightAlignedMultiselectScrollbars = "false"
            canRenderAfterInputOrSelectElement = "true"
            canRenderInputAndSelectElementsTogether = "true"
            canRenderOneventAndPrevElementsTogether = "true"
            canCombineFormsInDeck = "true"
            canRenderMixedSelects = "true"
            canRenderPostBackCards = "true"
            canRenderSetvarZeroWithMultiSelectionList = "true"
            supportsImageSubmit = "true"
            supportsSelectMultiple = "true"
            requiresHtmlAdaptiveErrorReporting = "false"
            requiresContentTypeMetaTag = "false"
            requiresDBCSCharacter = "false"
            requiresOutputOptimization = "false"
            supportsAccesskeyAttribute = "false"
            supportsInputIStyle = "false"
            supportsInputMode = "false"
            supportsIModeSymbols = "false"
            supportsJPhoneSymbols = "false"
            supportsJPhoneMultiMediaAttributes = "false"
            maximumRenderedPageSize = "2000"
            requiresSpecialViewStateEncoding = "false"
            requiresNoBreakInFormatting = "false"
            requiresLeadingPageBreak = "false"
            supportsQueryStringInFormAction = "true"
            supportsCacheControlMetaTag = "true"
            supportsUncheck = "true"
            canRenderEmptySelects = "true"
            supportsRedirectWithCookie = "true"
            supportsEmptyStringInCookieValue = "true"
            cachesAllResponsesWithExpires = "false"
            requiresNoSoftkeyLabels = "false"
            defaultSubmitButtonLimit = "1"
            supportsBold = "false"
            supportsItalic = "false"
            supportsFontSize = "false"
            supportsFontName = "false"
            supportsFontColor = "true"
            supportsBodyColor = "true"
            supportsDivAlign = "true"
            supportsDivNoWrap = "false"
            supportsCharacterEntityEncoding = "true"
            isMobileDevice="false"
        
</ browserCaps >

 

乱码问题,可以在WEB.CONFIG中设置:

 

< globalization    requestEncoding ="UTF-8"        responseEncoding ="UTF-8"   />

 

在OPERA或M3GATE中设置编码为UTF-3即可显示中文.

使用MS自带的移动控件可以很方便的建立网站,如LINK,COMMAND,LABEL等

 

使用ASP.NET开发移动通讯的几种方法 
http://www.yesky.com/35/1640535.shtml 

用VS2005实现ASP.NET2.0移动开发 
http://dev.yesky.com/msdn/293/2371793.shtml 

ASP.NET 2.0移动开发入门之基础 
http://dev.yesky.com/msdn/373/2411873.shtml 

ASP.NET 2.0移动开发入门之使用模拟器 
http://dev.yesky.com/msdn/465/2471465.shtml 

ASP.NET 2.0移动开发入门之使用样式 
http://dev.yesky.com/msdn/230/2486230.shtml 

ASP.NET 2.0移动开发之属性重写和模板化 
http://dev.yesky.com/msdn/90/2570590.shtml 

ASP.NET 2.0移动开发之定义设备筛选器 
http://dev.yesky.com/msdn/117/2579117.shtml
参考资料:http://dev.yesky.com

俺用的工具有点落后,vs2008 express版。没用过asp.net mobile 开发过wap网站,

  于是想尽各种办法用asp.net 给实现了:

  刚出了点状况,代码下载下载源代码

用asp.net开发移动wap网站集成在线wap模拟器

  注:通过目录下的/moni可以模拟浏览我们制作好的wap网站

  我们先实现一个Page类,添加一些于aspx页的交互,因为wap可能不支持viewState吧

  Page.cs 注意与System.Web.UI.Page分开哦

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Rsion.Web
{
    public abstract class Page : System.Web.UI.Page
    {
        private TempDatas<string, Object> tempData;
        public Page() { BindEvents(); }
        /// <summary>
        /// 页面临时数据
        /// </summary>
        public TempDatas<String, Object> TempData
        {
            get
            {
                if (tempData == null) tempData = new TempDatas<string, Object>();
                return tempData;
            }
        }
        public PageAdapter Html
        {
            get { return new PageAdapter(this); }
        }
        /// <summary>
        /// 绑定事件
        /// </summary>
        protected virtual void BindEvents()
        {
        }
    }
}

 Code


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using Rsion.Web;
namespace Rsion.Web
{
    public abstract class Application:System.Web.HttpApplication
    {
        public static Template Template;
        /// <summary>
        /// 模板缓存时间
        /// </summary>
        public static int TemplateCacheTime = 10;
        /// <summary>
        /// 重启Web进程
        /// </summary>
        public static void RestartWebProcess()
        {
            HttpRuntime.UnloadAppDomain();
        }
    }
}

  创建TempData用于与.aspx页数据交换


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
// Author : Sonven
// Blog   : Sonven.cnblogs.com
namespace Rsion.Web
{
    public class TempDatas<TKey,TValue>:CollectionBase
    {
        private Dictionary<TKey, TValue> dataArray;
        public TValue this[TKey key]
        {
            get
            {
                if (dataArray.ContainsKey(key))return dataArray[key];
                throw new ArgumentException("未添加此数据项进入该集合!", "TKey", null);
            }
            set
            {
                dataArray = dataArray ?? new Dictionary<TKey, TValue>();
                if (dataArray.ContainsKey(key)) dataArray[key] = value;
                else dataArray.Add(key, value);
            }
        }
        /// <summary>
        /// 添加一个键值数据
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public void Add(TKey key, TValue value)
        {
            dataArray=dataArray??new Dictionary<TKey,TValue>();
            dataArray.Add(key,value);
        }
    }
}

我们扩展Page类创建一个PageAdapter.cs  (用于添加模板支持)


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI;
using System.Web;
using System.IO;
using System.Text.RegularExpressions;
namespace Rsion.Web
{
    /// <summary>
    /// WebPage页面辅助适配器类
    /// </summary>
   public class PageAdapter
    {
       private Page page;
       public PageAdapter(Page page)
       {
           this.page = page;
       }
       /// <summary>
       /// 显示模板
       /// </summary>
       /// <param name="partialPath">模板文件路径:不带后缀[模板后缀.tpl]如/bottom将显示Templates下的bottom.tpl文件</param>
       public void RenderPartial(string partialPath)
       {
           string templateID="Template_"+partialPath.Replace("/", "_");
           object o =  HttpRuntime.Cache[templateID];
           if (o == null)
           {
               FileInfo fi = new FileInfo(HttpContext.Current.Server.MapPath("~/templates/" + partialPath + ".tpl"));
               if (!fi.Exists) return;
               string templateContent;
               using (StreamReader sr = new StreamReader(fi.FullName))
               {
                   templateContent = sr.ReadToEnd();
               }
               //转换
               TransformTemplateTags(ref templateContent);
               //写入缓冲
               HttpRuntime.Cache.Insert(templateID, templateContent, null,
                   DateTime.Now.AddMinutes(Application.TemplateCacheTime),TimeSpan.Zero);
               HttpContext.Current.Response.Write(templateContent);
           }
           else
               HttpContext.Current.Response.Write(o.ToString());
       }
       /// <summary>
       /// 转换模板内容
       /// </summary>
       /// <param name="templateContent"></param>
       private void TransformTemplateTags(ref string templateContent)
       {
           string templateID;
           string pattern=@"\${(\w+)}";
           Regex rg = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
           foreach(Match m in  rg.Matches(templateContent))
           {
               templateID = Regex.Replace(m.Captures[0].Value, pattern, "$1");
               templateContent = Regex.Replace(templateContent, @"\${" + templateID + "}",
                   Application.Template.Rules[templateID].ToString());
           }
       }
       /// <summary>
       /// 转换该页的标签内容
       /// </summary>
       public void TransformPageTags()
       {
           ///
           ///TO:DO..
           ///
       }
    }
}

 现在我们要实现可以用于wap的page类了,WapPage.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.IO;
// Author : Sonven
// Blog   : Sonven.cnblogs.com
namespace Rsion.Web
{
    public class WapPage:Page
    {
        public WapPage() : base() { }
        /// <summary>
        /// 绑定事件
        /// </summary>
        protected override void BindEvents()
        {
            Page.Load += delegate(object s, EventArgs e)
            {
                HttpContext.Current.Response.Write("<?xml version=\"1.0\"?>\r" +
                    "<!DOCTYPE wml PUBLIC \"-//WAPFORUM//DTD WML 1.1//EN\" \"http://www.wapforum.org/DTD/wml_1.1.xml\">\r");
            };
            Page.LoadComplete += delegate(object s, EventArgs e)
            {
                HttpContext.Current.Response.ContentType = "text/vnd.Web.wml";
            };
            //处理错误时候转向错误页面[仅在发布后]
            #if DEBUG
            #else
            Page.Error += delegate(object s, EventArgs e)
            {
                Session["errormsg"] = HttpContext.Current.Error.Message + "<br />" +
                    "地址:" + HttpContext.Current.Request.RawUrl.ToString();
                HttpContext.Current.Response.Redirect("~/error.aspx");
            };
            #endif
            Page.PreRender += delegate(object s, EventArgs e)
            {
            };
        }
    }
}

 这样就差不多只要继承WapPage就可以实现wap网页开发了

  接下来我们创建模板,并给模板加上缓存提高性能

  Application.cs用于提供缓存时间

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using Rsion.Web;
namespace Rsion.Web
{
    public abstract class Application:System.Web.HttpApplication
    {
        public static Template Template;
        /// <summary>
        /// 模板缓存时间
        /// </summary>
        public static int TemplateCacheTime = 10;
        /// <summary>
        /// 重启Web进程
        /// </summary>
        public static void RestartWebProcess()
        {
            HttpRuntime.UnloadAppDomain();
        }
    }
}

  接下来我们创建一个单独的Template项目先

  在里面创建Template.cs,ParamRules

  ParamRules实现如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
namespace Rsion.Web
{
    /// <summary>
    /// 模板参数规则类
    /// </summary>
    public class ParamRules:IEnumerable
    {
        private Dictionary<string, object> rules;
        public ParamRules()
        {
            if (rules == null) rules = new Dictionary<string, object>();
        }
        public object this[string paramKey]
        {
            get
            {
                if (rules.ContainsKey(paramKey)) return rules[paramKey];
                return "";
            }
            set
            {
                if (rules.ContainsKey(paramKey)) rules[paramKey] = value;
                else rules.Add(paramKey, value);
            }
        }
        /// <summary>
        /// 添加新的规则
        /// </summary>
        /// <param name="paramKey"></param>
        /// <param name="paramValue"></param>
        public void Add(string paramKey, object paramValue)
        {
            if (rules.ContainsKey(paramKey))
                throw new ArgumentException("对不起规则已经存在!Key:" + paramKey + ",Value:" + rules[paramKey].ToString(), "paramKey");
            rules.Add(paramKey, paramValue);
        }
        public void Remove(string paramKey, object paramValue)
        {
            if (rules.ContainsKey(paramKey))
                rules.Remove(paramKey);
        }
        #region IEnumerable 成员
        public IEnumerator GetEnumerator()
        {
            foreach (KeyValuePair<string, object> k in rules)
            {
                yield return k;
            }
        }
        #endregion
    }
}

Template.cs实现如下:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Rsion.Web
{
    /// <summary>
    /// 模板
    /// </summary>
    public class Template
    {
        public static Template _template;
        private static ParamRules rules;
        private Template() { }
        public static Template CreateInstance()
        {
            if (_template == null) _template = new Template();
            return _template;
        }
        public ParamRules Rules
        {
            get
            {
                if (rules == null) rules = new ParamRules();
                return rules;
            }
        }
        
    }
}

  这样我们先在global.asax中填加一些模板数据,这样才可以解析模板,解析模板的功能实现在PageAdapter中,这样可以

  在本页面直接调用Html.RenderPartial("template")调用

  gobal.asax


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using Rsion.Web;
using c=Rsion.Web.Config;
namespace Rsion.Wap
{
    public class Global : System.Web.HttpApplication
    {
        protected void Application_Start(object sender, EventArgs e)
        {
            InitTemplate();//初始化模板数据,只针对那些不经常变化的数据
        }
        # region events
        protected void Session_Start(object sender, EventArgs e)
        {
        }
        protected void Application_BeginRequest(object sender, EventArgs e)
        {
        }
        protected void Application_AuthenticateRequest(object sender, EventArgs e)
        {
        }
        protected void Application_Error(object sender, EventArgs e)
        {
        }
        protected void Session_End(object sender, EventArgs e)
        {
        }
        protected void Application_End(object sender, EventArgs e)
        {
        }
        #endregion
        private void InitTemplate()
        {
            global::Rsion.Web.Template t = Template.CreateInstance();
            //添加模板数据规则,只用于不常更新的数据  如key=webname 则{$webname}替换成value
            t.Rules.Add("webname",c.Web.Current.WebName);
            t.Rules.Add("weburi", c.Web.Current.WebUri);
            t.Rules.Add("sysname", "sonven's wap develop framework!");
            Rsion.Web.Application.Template = t;
            //模板缓存过期时间(分钟)(默认10分钟)
            Rsion.Web.Application.TemplateCacheTime = 0;
        }
    }
}

 然后着手开发wap项目了

  首先新建一个default.aspx,default.aspx.cs

  两文件如下


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Rsion.Web.Config;
using Rsion.Web;
namespace Rsion.Wap
{
    public partial class Default:WapPage
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                TempData.Add("webname", Gobal.Web.WebName);
                TempData.Add("webUri", Gobal.Web.WebUri);
            }
        }
    }
}

  default.aspx


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Rsion.Wap.Default" %>
<wml>
<head></head>
<card title="<%=TempData["webname"] %>">
    <%Html.RenderPartial("top"); %>
    <%Html.RenderPartial("index"); %>
    数据绑定用&lt;%=TempData[id] %&gt;<br /><br />调用显示模板&lt;% Html.RenderPartial(&quot;<br />模板在Templates下的路径不包括.tpl)<br />
    模板中用:${templateId}代替符号<br />
    然后在使用Rsion.Web.Application.<br />Template.Rules.Add(templateID,value)<br />
    就可以调出value值了!
    
    <%Html.RenderPartial("bottom"); %>
</card>
</wml>

 怎么样呢是不是很简单,接着创建模板

  文件放在/Templates/下哦,文件扩展为.tpl

  bottom.tpl


<br />
<a href="/">首页</a> | 
<a href="http://www.cnyolee.com">有理网</a> |
<a href="http://sonven.cnblogs.com">博客园</a> |
<a href="http://www.rsion.com">联系我</a>
<br />
 ${webname} ${weburi}

  同理创建其他的模板

  我们在Page类里面实现了友好的自定义错误页,我们创建显示这个页面的error.aspx

  error.aspx

  Code


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Error.aspx.cs" Inherits="Rsion.Wap.Error" %>
<wml>
<card title="对不起出错了!">
    手机锐讯网 Web.rsion.com <br />
    错误信息:<br />
    <%=TempData["errormsg"]%>
</card>
</wml>

  Code


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Rsion.Web;
namespace Rsion.Wap
{
    public partial class Error:WapPage
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
               this.TempData["errormsg"] = Session["errormsg"] ?? "系统执行出错!";
            }
        }
    }
}

 

  Ok了接下来就该验收结果了,达开/moni在里面输入你的地址就可以看到wap已经可以正常在浏览器中显示了

本文示例源代码或素材下载

你可能感兴趣的:(asp.net)