[Flash]Flash与Silverlight终极大比拼

mikel阅读(805)

自 Silverlight 1.0 发布以来,Web 开发与设计者们关于该选择 Flash 和 Silverlight的争论便开始了,在成熟的 Flash 面前,Silverlight 面临着如何赢得市场的难题。然而 Silverlight中包含了一些开发设计者们一直希望 Flash 能拥有的功能,诸如SEO,本文对 Flash 和 Silverlight的技术细节进行了详尽的对比。

动画功能

Flash 使用基于帧的动画模式,在逐帧动画模式中,我们为每个帧创建对象并生成动画序列。比如你想让一个对象在3秒内穿过屏幕,计算一下3秒一共有多少帧,然后计 算每帧需要的矩阵。不过 Flash 在实际播放中并不会真实地按设定的帧率播放,除非你在动画中插入一条空白的音轨。

Silverlight 基于 WPF 动画模式,WPF 是基于时间线,而不是帧的,你定义好起始于结束状态,WPF 帮你计算中间该怎么做,不必象 Flash 那样同矩阵打交道,也不必计算在不同帧对象的位置。

文件尺寸

Flash 使用压缩格式,文字和图片内嵌在整个文件中,因此 Flash 的文件尺寸非常小巧。

Silverlight 使用 XAML 作为描述语言,未经过压缩,因此 Silverlight 的文件尺寸通常要大一些。

脚本

Flash 使用 ActionScript, ActionScript 面向对象,对用户界面设计有全面的控制,还可以同其它后端语言,如 PHP, ASP, Ruby On Rails 进行集成交流,拥有一个强大的开发库。

Silverlight 的脚本可以选择多种开发语言,Visual C#.Net and Visual Basic.Net,也包括客户端语言 JavaScriptC# 和 VB.net 可以用来编写托管代码,并可以全面使用 .net 框架库。

视频和音频

Flash 支持多种音频格式,最新的音频解码器质量非常高,而带宽占用也非常出色。它的视频解码器,Sorenson 的专用 H.263 是 H.263 的变种,压缩也接近,但去掉了一些功能。

Silverlight 使用的是行业标准 VC-1 视频解码,并支持 WMV 和 WMA,Windows Movie Maker 可以很容易产生这两种格式,同时微软还提供免费的 WMV, WMA 编码器。

声音处理

ActionScript 提供了一套声音类库,可以用来在动画中生成或控制声音,你可以在动画播放期间从资源库加入声音,同时 Flash 还有一些方法在整个动画中控制声音。

Silverlight 没有底层声音控制 API,甚至无法播放一个 WAV 文件,因为 .NET 在音频播放上很薄弱。

可访问性

对那些有视觉或听觉缺陷的人,Flash 提供了丰富的可访问性功能,视频字幕可以帮助听觉障碍者,而那些视觉障碍者需要通过键盘控制声音的播放,人们可以使用键盘快捷键控制视频播放。



Silverlight 3 首次提供对全部系统配色的支持,那些视力不佳的人可以调整到高对比度配色方案,在可访问性方面 Silverligth 比 Flash 差很多。

平台兼容性

Flash 支持 Windows Vista/XP/2000, Windows Server 2003/2008, Mac OS 10.1/10.5(PowerPC), Mac OS 10.1/10.5 (Intel), Linux 5, openSUSE 11, Ubuntu 7.10or later and Solaris 10.
Silverlight 只支持 Windows Vista/XP/2000,Windows Server 2003/2008, Windows Mobile 6, Mac OS 10.1/10.5 (PowerPC)and Mac OS 10.1/10.5 (Intel)。由于不支持 Linux 和 Solaris,因此这些平台的用户无法体验Silverlight 。(不过 .NET 在 Linux 平台的第三方开源项目,MONO 框架中的 MoonLight 支持 Linux -译者)

文字展示与SEO

Flash 中的文字是基于图形的,Flash 播放器无法理解 TTF,因此我们无法从 Flash动画中分离出文字。通常,Flash 对 SEO 是不友好的,但 Adobe 已经做出一些努力让 Flash中的文字可以索引,而搜索引擎也开始尝试索引 Flash 了。目前,Google 是唯一支持 Flash 索引的搜索引擎,他们同 Adobe合作,设计相应的可以理解 Flash 内容的 Google 爬虫。 Yahoo 正在进展中,鉴于微软的 Silverlight 是 Flash的竞争者,他们不大可能在 MSN 中索引 Flash。
Silverlight 是基于 XAML 的,Silverlight 中的文字内容是独立存放的,可以被任何搜索引擎索引,因此对搜索引擎更友好。

支持的图片格式

Flash 支持几乎所有图片格式。Silverlight 只支持 PNG 与 JPEG,其它格式提供有限的支持。

网络编程

Flash 使用 XMLSocket 和服务器进行沟通。

Silverlight 通过 System.Net.Sockets 命名空间,对网络编程提供全面支持,Silverlight 可以通过 4502 到 4534 端口异步传输数据,也支持跨域通讯。

摄像头的支持

Flash 支持网络摄像头和麦克风,使用 ActionScript 可以很容易操控摄像头或麦克风。Silverlight 不支持摄像头和麦克风。

部署

Flash 的部署只包含一个独立的 SWF 文件,这个文件已经包含了所有图片,文字,动画。Silverlight 的部署要复杂一些,所有独立的部件都要单独部署,典型的 Silverlight 请求一般包含以下内容:

  • XML 文件,
  • DLL 文件(如果有),
  • Silverlight.js,
  • 其它JavaScript 文件,
  • 资源文件 (图片,视频,音频)
  • Windows 可执行文件

    Flash 动画可以编译成独立的 Windows 可执行程序,在桌面播放。

    Silverligth 不支持。

    流媒体服务

    Flash 不支持流媒体服务(虽然 FLV 控制了几乎所有视频网站,但那是另一回事-译者)。
    微软基于 Windows Live 的 Silverlight 流媒体服务可以让设计和开发者分发富媒体,结合微软的 Expression Studio,开发与设计者们可以创建交互式 Web 程序。

    结论

    富Internet 应用的技术选择向来存在很多争议,在 Silverlight 和 Flash 中选择,完全要看你的需求,如果你的用户包括Linux 和 Solaris 平台的,Flash 是不二之选,如果希望你的网站可以被索引,Silverlight 更好一些。
    另外需要指出的 是,安装了 Silverligth 插件的用户尚在少数,而绝大多数用户的浏览器中都安装了 Flash 插件,另外,SWF,FLA, FLV 几乎成了开发标准格式,而 Silverligth 还是100%私有格式(然而 Silverlight已经是明文了,还谈什么开放不开放 – 译者)。

    本文国际来源:Flash vs. Silverlight: What Suits Your Needs Best?
    中文翻译来源:COMSHARP CMS 官方网站

    [Java]WEB4J:另类的Java Web应用框架

    mikel阅读(1131)

    WEB4J是个极度简化、特色十足、一站式的Java Web框架。WEB4J框架的创建者John O'Hanley说到:WEB4J在提升Java开发生产力的同时又消除了各种痛苦,因为其非常精简且能显著地加快应用开发的速度。

    根据其站点上的说明,WEB4J具有如下特性:

    • 拥抱约定优于配置(类似于Rails)
    • 数据为王,而不是代码
    • 不会强迫开发者穿新鞋走老路
    • 不依赖于JavaScript、客户化的XML和注解以及对象关系映射
    • 不会对你所编写的类施加线程安全的约束
    • 可以用普通的HTML编写表单

    WEB4J最吸引人的一个地方就是它可以将SQL放到纯文本文件中且游离于代码之外,之后就可以在代码中通过特殊的对象引用这些SQL,这样DAO类就变得非常紧凑了。

    WEB4J个头很小,一共才88个类,而Rails中却有346个类、Struts中有720个类、Spring中有2400多个类。John说WEB4J的学习要比其他框架容易的多。

    其站点对WEB4J的薄弱之处也毫不掩饰:

    • 没有用户界面widgets库
    • 未提供对AJAX、Web Services及依赖注入的内置支持
    • 支持JSP/JSTL,但却没有像Velocity那样的标记库
    • 对之前版本的兼容性还有些问题

    去年YouTube上有个挺逗的视频谈到了WEB4J框架。该视频说的是有两个程序员发现了WEB4J框架后就用其进行开发,从而摆脱了传统的J2EE项目所遇到的诸多痛苦。

    WEB4J是开源的,基于BSD协议,同时在其分发包中含有一个示例项目。

    查看英文原文:WEB4J: Contrarian Web App Development for Java

    [Json]Json.Net

    mikel阅读(860)

    转载:http://www.rainsts.net/article.asp?id=817
    JSON 应用愈发广泛,相对 XML 而言,JSON 格式的数据量更小,更利于传输和存储。在 Ajax、Data Service、Silverlight 等框架中都有大量应用。但 .NET Framework 对 JSON 的支持还很弱,由于无法使用动态类型,因此 JavaScriptSerializer().DeserializeObject() 只是简单地将 "未知类型" 的目标反序列化为一个泛型词典(Dictionary),看上去像个半成品。
    CodePlex Json.NET 是另外一种选择,作者特意提供了一个 JsonConvert.DeserializeAnonymousType(),使得我们可以用一个匿名对象实例来指定反序列化类型。

    var o = new
    {
      a = 1,
      b = "Hello, World!",
      c = new[] { 1, 2, 3 },
      d = new Dictionary<string, int> { { "x", 1 }, { "y", 2 } }
    };
    var json = JsonConvert.SerializeObject(o);
    var anonymous = new { a = 0, b = String.Empty, c = new int[0], d = new Dictionary<string, int>() };
    var o2 = JsonConvert.DeserializeAnonymousType(json, anonymous);
    Console.WriteLine(o2.b);
    Console.WriteLine(o2.c[1]);
    var o3 = JsonConvert.DeserializeAnonymousType(json, new { c = new int[0], d = new Dictionary<string, int>() });
    Console.WriteLine(o3.d["y"]);

    DeserializeAnonymousType 只是借助这个匿名对象参数(anonymous) 反射类型而已,也就是说它和反序列化结果并非同一个对象。正如 o3 那样,我们也可以只提取局部信息。
    实际上,我们也可以直接反序列化为 JObject,然后通过索引器直接访问。JObject、JProperty 等都继承自 JToken,它重载了基元类型转换操作符,我们可以直接得到实际结果。

    var o = new
    {
      a = 1,
      b = "Hello, World!",
      c = new[] { 1, 2, 3 },
      d = new Dictionary<string, int> { { "x", 1 }, { "y", 2 } }
    };
    var json = JsonConvert.SerializeObject(o);
    var o2 = JsonConvert.DeserializeObject(json) as JObject;
    Console.WriteLine((int)o2["a"]);
    Console.WriteLine((string)o2["b"]);
    Console.WriteLine(o2["c"].Values().Count());
    Console.WriteLine((int)o2["d"]["y"]);

    Json.NET 同样支持强类型特性标注和反序列化,同时还提供了几个常用的格式转换器。

    [JsonObject]
    class MyClass
    {
      [JsonProperty]
      public int a { get; set; }
      [JsonProperty]
      public string b { get; set; }
      [JsonProperty]
      public int[] c { get; set; }
      [JsonProperty]
      public Dictionary<string, int> d { get; set; }
      [JsonIgnore]
      public float e { get; set; }
      [JsonProperty]
      [JsonConverter(typeof(IsoDateTimeConverter))]
      public DateTime f { get; set; }
    }
    class Program
    {
      static void Main(string[] args)
      {
        var o = new MyClass
        {
          a = 1,
          b = "Hello, World!",
          c = new[] { 1, 2, 3 },
          d = new Dictionary<string, int> { { "x", 1 }, { "y", 2 } },
          f = DateTime.Now
        };
        var json = JsonConvert.SerializeObject(o);
        var o2 = JsonConvert.DeserializeObject<MyClass>(json);
      }
    }

    LINQ to JSON 看上去有点像 LINQ to XML,使用非常简单,有关详情可参考帮助文件。

    [MVC]Asp.net MVC 示例项目"Suteki.Shop"分析之---Controller

    mikel阅读(786)

    转载http://www.cnblogs.com/daizhj/archive/2009/05/12/1451955.html   

     在上文中,介绍了如何安装和使用Suteki,今天我们通过源码来看一下Suteki是如何使用
    Controller。

         在Suteki中,其使用Abstract的方式来定义一个ControllerBase,以此作为所有Controller
    的基类,下面是其Controller的类设计图:

        
        
          在该基类中定义了一些Controller中常用到的方法,比如为当前视图添加MetaDescription,
    Title等:   

    [Rescue("Default"), Authenticate, CopyMessageFromTempDataToViewData]
    public abstract class ControllerBase : Controller, IProvidesBaseService
    {
            
    private IBaseControllerService baseControllerService;
            
    /// <summary>
            
    /// Supplies services and configuration to all controllers
            
    /// </summary>
            public IBaseControllerService BaseControllerService
            {
                
    get { return baseControllerService; }
                
    set 
                { 
                    baseControllerService 
    = value;
                    ViewData[
    "Title"= "{0}{1}".With(
                        baseControllerService.ShopName,
                        GetControllerName());
                    ViewData[
    "MetaDescription"= "\"{0}\"".With(baseControllerService.MetaDescription);
                }
            }
            
    public ILogger Logger { getset; }
            
    public virtual string GetControllerName()
            {
                
    return " – {0}".With(GetType().Name.Replace("Controller"""));
            }
            
    public virtual void AppendTitle(string text)
            {
                ViewData[
    "Title"= "{0} – {1}".With(ViewData["Title"], text);
            }
            
    public virtual void AppendMetaDescription(string text)
            {
                ViewData[
    "MetaDescription"= text;
            }
         
    public string Message
         {
       
    get { return TempData["message"as string; }
       
    set { TempData["message"= value; }
         }
      
    protected override void OnException(ExceptionContext filterContext) {
       Response.Clear();
       
    base.OnException(filterContext);
      }
    }

        

          当然,细心的朋友发现了该抽象类中还包括一个IBaseControllerService接口实例。
    该接口的主要定义了一些网店系统信息,如店铺名称,版权信息,Email信息等,如下:

    public interface IBaseControllerService
    {
        IRepository
    <Category> CategoryRepository { get; }
        
    string GoogleTrackingCode { getset; }
        
    string ShopName { getset; }
        
    string EmailAddress { getset; }
        
    string SiteUrl { get; }
        
    string MetaDescription { getset; }
        
    string Copyright { getset; }
        
    string PhoneNumber { getset; }
        
    string SiteCss { getset; }
    }

       

          而作为唯一一个实现了该接口的子类“BaseControllerService”定义如下:  

    public class BaseControllerService : IBaseControllerService
    {
            
    public IRepository<Category> CategoryRepository { getprivate set; }
            
    public string GoogleTrackingCode { getset; }
            
    public string MetaDescription { getset; }
            
    private string shopName;
            
    private string emailAddress;
            
    private string copyright;
            
    private string phoneNumber;
            
    private string siteCss;
            ..
    }

        
          而初始化BaseControllerService实例并将配置文件中的信息绑定到该类实例中的操作交给了Windsor,
    该组件在Castle中用于实现IOC操作,其配置文件位于项目Suteki.Shop\Configuration\Windsor.config.
    下面是其配置结点内容:

    <component
      id
    ="IBaseControllerService:test.jumpthegun.co.uk"
      service
    ="Suteki.Shop.Services.IBaseControllerService, Suteki.Shop"
      type
    ="Suteki.Shop.Services.BaseControllerService, Suteki.Shop"
      lifestyle
    ="transient">
      
    <parameters>
        
    <ShopName>Suteki Shop</ShopName>
        
    <EmailAddress>info@sutekishop.co.uk</EmailAddress>
        
    <GoogleTrackingCode>UA16436774</GoogleTrackingCode>
        
    <MetaDescription>Suteki Shop is a new self service eCommerce solution. Search engine optimised and fully customisable</MetaDescription>
        
    <SiteCss>Site.css</SiteCss>
      
    </parameters>
    </component>

        
         这类就完成了把网店的系统信息绑定到Controller中的操作,而Controller就会在其基类中将相关的
    信息绑定到ViewData中,如下: 

     ViewData["Title"= "{0}{1}".With(baseControllerService.ShopName, GetControllerName());
     ViewData[
    "MetaDescription"= "\"{0}\"".With(baseControllerService.MetaDescription);

     
     
         到这里,其实大家应该发现这种对Controller的处理与我们以前所使用的PageBase方式相似,就是将
    项目中所有的Page都继承自PageBase,然后在相应的Page中引用PageBase中定义的属性和方法。

         有了ControllerBase,我们看一下在相应的子Controller中是如何使用的,这里有一个例子,
    ProductController(位于Suteki.Shop\Controllers\ProductController.cs): 
       

    public class ProductController : ControllerBase
    {
        
        
     
    public ActionResult Item(string urlName)
     {
      
    return RenderItemView(urlName);
     }
        ..
        
     ActionResult RenderItemView(
    string urlName)
     {
      var product 
    = productRepository.GetAll().WithUrlName(urlName);
      AppendTitle(product.Name);
      AppendMetaDescription(product.Description);
      
    return View("Item", ShopView.Data.WithProduct(product));
     } 
     
    }

     

          该Controller中的Action:"Item"调用了RenderItemView()就是使用了基类中的AppendTitle,
    AppendMetaDescription。下面是其运行时的截图:
        
            

            
        
          除了上面所说的这种ControllerBase方式,Suteki.Shop还使用了Controller<T>方式来实现对
    一些公用Action的操作,比如列表,编辑,添加记录,调整记录上下位置等。而这块实现代码被放
    置在了Suteki.Common\ScaffoldController.cs和OrderableScaffoldController.cs文件中,其中
    ScaffoldController为父类,其中包括列表,编辑,添加Action等。

     


    public class ScaffoldController<T> : Controller where T : classnew()
    {
        
    public IRepository<T> Repository { getset; }
        
    public IRepositoryResolver repositoryResolver { getset; }
        
    public IValidatingBinder ValidatingBinder { getset; }
        
    public IHttpContextService httpContextService { getset; }
        
    public virtual ActionResult Index(int? page)
        {
            
    return RenderIndexView(page);
        }
        
    protected virtual ActionResult RenderIndexView(int? page)
        {
            var items 
    = Repository.GetAll().AsPagination(page ?? 1);
            
    return View("Index", ScaffoldView.Data<T>().With(items));
        }
        
    public virtual ActionResult New()
        {
            var item 
    = new T();
            
    return View("Edit", BuildEditViewData().With(item));
        }
     
     [AcceptVerbs(HttpVerbs.Post)]
     
    public ActionResult New([DataBind(Fetch = false)] T item)
     {
      
    if(ModelState.IsValid)
      {
       Repository.InsertOnSubmit(item);
       TempData[
    "message"= "Item successfully added."
       
    return RedirectToAction("Index");
      }
      
    return View("Edit", BuildEditViewData().With(item));
     }
        [NonAction]
        
    public virtual ScaffoldViewData<T> BuildEditViewData()
        {
            var viewData 
    = ScaffoldView.Data<T>();
            AppendLookupLists(viewData);
            
    return viewData;
        }
        
    public virtual ActionResult Edit(int id)
        {
            T item 
    = Repository.GetById(id);
            
    return View("Edit", BuildEditViewData().With(item));
        }
     [AcceptVerbs(HttpVerbs.Post)]
     
    public virtual ActionResult Edit([DataBind] T item)
     {
      
    if(ModelState.IsValid)
      {
       TempData[
    "message"= "Item successfully updated.";
       
    return RedirectToAction("Index");
      }
      
    return View("Edit", BuildEditViewData().With(item));
     }
        
    public virtual ActionResult Delete(int id, int? page)
        {
            T item 
    = Repository.GetById(id);
            Repository.DeleteOnSubmit(item);
            
    //Repository.SubmitChanges();

            
    return RedirectToAction("Index"new {page});
        }
        
    /// <summary>
        
    /// Appends any lookup lists T might need for editing
        
    /// </summary>
        
    /// <param name="viewData"></param>
        [NonAction]
        
    public virtual void AppendLookupLists(ScaffoldViewData<T> viewData)
        {
            
    // find any properties that are attributed as a linq entity
            foreach (var property in typeof(T).GetProperties())
            {
                
    if (property.PropertyType.IsLinqEntity())
                {
                    AppendLookupList(viewData, property);
                }
            }
        }
        
    private void AppendLookupList(ScaffoldViewData<T> viewData, PropertyInfo property)
        {
            var repository 
    = repositoryResolver.GetRepository(property.PropertyType);
            
    // get the items
            object items = repository.GetAll();
            
    // add the items to the viewData
            viewData.WithLookupList(property.PropertyType, items);
        }
    }

       

         大家请注意ScaffoldController类中的几个公共属性:   

        public IRepository<T> Repository { getset; }
        
    public IRepositoryResolver repositoryResolver { getset; }
        
    public IValidatingBinder ValidatingBinder { getset; }
        
    public IHttpContextService httpContextService { getset; }

       

          其中Repository是一些对数据CRUD的操作对象,下面是Repository中的一些接口成员方法:

    public interface IRepository<T> where T : class
    {
        T GetById(
    int id);
        IQueryable
    <T> GetAll();
        
    void InsertOnSubmit(T entity);
        
    void DeleteOnSubmit(T entity);
        [Obsolete(
    "Units of Work should be managed externally to the Repository.")]
        
    void SubmitChanges();
    }

     

          这样就可以在ScaffoldController使用统一的接口函数调用相应子类中的实现方法了。   

          而ScaffoldController的子类OrderableScaffoldController则实现了对数据集合中的某行元素
    上下移动的操作:
       

    public class OrderableScaffoldController<T> : ScaffoldController<T> where T : class, IOrderable, new()
    {
        
    public IOrderableService<T> OrderableService { getset; }
        
    protected override ActionResult RenderIndexView(int? page)
        {
            var items 
    = Repository.GetAll().InOrder().AsPagination(page ?? 1);
            
    return View("Index", ScaffoldView.Data<T>().With(items));
        }
        
    public override ActionResult New()
        {
            T item 
    = new T
            {
                Position 
    = OrderableService.NextPosition
            };
            
    return View("Edit", (object)BuildEditViewData().With(item));
        }
       [UnitOfWork]
        
    public virtual ActionResult MoveUp(int id, int? page)
        {
            OrderableService.MoveItemAtPosition(id).UpOne();
      
    return RedirectToAction("Index");
        }
        [UnitOfWork]
        
    public virtual ActionResult MoveDown(int id, int? page)
        {
            OrderableService.MoveItemAtPosition(id).DownOne();
      
    return RedirectToAction("Index");
        }
    }

       

         注:IOrderableService的实现相对复杂一些,具体内容详见Suteki.Common\Services\OrderableService.cs.
         
         按说有了这些功能之后,只要在相应的子类中直接继承使用就可以了,但在Suteki.Shop项目中
    作者又对OrderableScaffoldController进行了一个“继承式”扩展,提供了与前面所说的那个“
    ControllerBase"相似的方法定义,如下:

    [Authenticate, CopyMessageFromTempDataToViewData]
    public abstract class ShopScaffoldController<T> : OrderableScaffoldController<T>, IProvidesBaseService where T : class, IOrderable, new()
    {
        
    private IBaseControllerService baseControllerService;
        
    /// <summary>
        
    /// Supplies services and configuration to all controllers
        
    /// </summary>
        public IBaseControllerService BaseControllerService
        {
            
    get { return baseControllerService; }
            
    set
            {
                baseControllerService 
    = value;
                ViewData[
    "Title"= "{0}{1}".With(
                    baseControllerService.ShopName,
                    GetControllerName());
            }
        }
        
    public virtual string GetControllerName()
        {
            
    return " – {0}".With(GetType().Name.Replace("Controller"""));
        }
    }

       

         而ShopScaffoldController这个抽象类有三个子类,如下图:
      
        

          因为这三个Controller的功能需求相似,而相应的Action实现也在基类“ScaffoldController”
    中实现,所以相应的类代码基本上就没有什么了。只不过在这几个子类中都被绑定了UnitOfWork过滤
    器(UnitOfWorkFilter),其代码如下Suteki.Common\Filters\UnitOfWorkAttribute.cs

    public class UnitOfWorkAttribute : FilterUsingAttribute
    {
     
    public UnitOfWorkAttribute() : base(typeof (UnitOfWorkFilter))
     { }
    }
    public class UnitOfWorkFilter : IActionFilter
    {
     
    private readonly IDataContextProvider provider;
     
    public UnitOfWorkFilter(IDataContextProvider provider)
     {
      
    this.provider = provider;
     }
     
    public void OnActionExecuting(ActionExecutingContext filterContext)
     {}
     
    public void OnActionExecuted(ActionExecutedContext filterContext)
     {
      var context 
    = provider.DataContext;
      
    if (filterContext.Controller.ViewData.ModelState.IsValid)
      {
       context.SubmitChanges();
      }
     }
    }

        
          其核心功能就是在对用户提交的数据进行有效验证后调用DataContext的SubmitChanges()方法
    (注:该逻辑被放在了OnActionExecuted方法中实现)来保存修改,这种做法在以往的MVC示例子没有
    看到过,呵呵,不过这种做法还有待研究。


          好了,今天的内容就先到这里了,在下一篇中,将来讨论一下该项目中对MVC框架中Filter的用
    法。

          原文链接: http://www.cnblogs.com/daizhj/archive/2009/05/07/1451955.html

          作者: daizhj,代震军,LaoD

          Tags: mvc

          网址: http://daizhj.cnblogs.com/

    [MVC]Asp.net MVC 示例项目"Suteki.Shop"分析之---安装篇

    mikel阅读(766)

    转载:http://www.cnblogs.com/daizhj/archive/2009/05/11/1451925.html

    Asp.net MVC 示例项目"Suteki.Shop"分析之—安装篇

          声明:作为这个系列的开篇,本系统会将我在研究这个项目源码中的一些思考和心得介绍给大家。
    当然本系统决不是那种所谓的“最佳示范”,里面所提到的使用技巧或设计思路只是给大家在实际工
    作中提供一个参考,所谓“最好”之类的词汇都是“矬子里拔将军”,相信大家在成功的分析了几个
    MVC示例之后,会找到适合自己所在团队或公司使用的方式或思路的。 其实在找一个合适的MVC示
    例上我已花费了“一些”时间,而这个例子对于我来说,还是相对不错的(除了文档和相关说明较少
    之外)。另外,该项目还使用了其他一些框架或DLL文件,比如castle, MvcContrib, NVelocity
    这些内容会在后续文章中讲到。

         首先要解释一下这是个什么东东,其实说明了,Suteki就是一个在线商店一个B2C示例,用户可
    以在这里挑选自己喜欢的商品并通过在线支付功能进行购买。同时它还提供了一套相对完备的管理机
    制让管理员可以轻松管理自己的商品信息,分类信息,定单信息。总之这是一个相对完备的系统,尽
    管Suteki还没有被广泛安装和使用,并已有一些网站在使用它了,大家可以通过这个地址来看一下其
    运行实例:
    http://sutekishop.co.uk/

         这个项目源码下载地址:
        
    http://code.google.com/p/sutekishop/downloads/list
       
         关于该项目的BLOG:http://mikehadlow.blogspot.com/search/label/Suteki%20Shop, 只
    可惜内容少的可怜:(

         下面我们就看一下如何安装和实始化一个sutekishop。
       
         首先,我们要运行下载包中的SQL脚本以生成数据库并初始化相应数据。SQL文件位于Database
    件夹下的create_database.SQL(创建数据库和表),insert_static_data(初始化数据)。
         因为作者是个英国人,其所使用的数据库脚本与我们国内的中文版SQL会有所不同,而本人所运行
    的SQL2005是中文的,所以如直接运行create_database中的内容可能会出现一些异常。好在后来我
    其中的一些导致出错的内容从create_database中摘了出来发现能安装了,所以下面就将我修改过的
    sql脚本内容发上来(文章末尾),大家下载运行一下就可完成数据库的安装了。

        注:项目中的一些“数据库链接串”要批量替换成我们本地的数据库。
       
        接着,我们就在来一下最终的运行效果:)

        
            
        当点击页面右下方的Login链接时,会显示登陆提示框,我们在这里填入:      

        Email : admin@sutekishop.co.uk
        Password: 123123

        
        点击“SubmitQuery”按钮:
        
            
       

         这样我们就以管理员身份登入系统了,这时在顶部会出现相关的管理菜单,我们可以使用它来创建
    商品分类,商品信息,所在地信息,User信息等等。
       
           
     

          这里以创建User信息为例进行说明,点击“User”链接:
        
         

          大家看到这里我之前已创建了几个用户信息,同时还包括管理员信息“admin@sutekishop.co.uk”,
    (注:目前列表只显示Role为Administrator或Order Processor的信息)

     

        我们点击其中的“New User”链接,进入到添加用户页,并添入下列信息:        
        Email:
    test@sample.com
        Password :123123
        Role:Customer
       
        然后点击“Save”按钮:)

           
        
         这样我们就可以在前台以该用户身份进行登陆了。  
        
         同理,我们再去添加“Categories”,“Countries”等信息之后,相应的结果如下所示:    
        
            
           
       

         完成相关的设置之后,就可以购买商品了。
       
         下面以刚才新创建的
    test@sample.com帐号登陆系统,点击“Movie”–>“动作片”:
        
            
        
        我们点击该分类下的电影,比如这个“勇闯夺命岛”之后,进入到“购买流程”。
        
            
       

         点击“Add to basket”之后,就会显示一个购买清单:  

        
       

          我们在确认当前的购买信息之后,就可以点击“Checkout ”链接了:
           
          在接下来的付款环节里,就要填写相应的支付卡,地址等信息了。这个流程只要在线买过东西
    的朋友应该不会陌生。

            
     

        注:这里对信用卡校验的逻辑可能会麻烦一些,如果想跳这该校验,可以注释下面代码,位于:
         Suteki.Shop\Suteki.Common\Validation\ValidationExtensions.cs    

    public ValidationProperty<T> IsCreditCard()
    {
        
    if (IsString)
        {
            var trimmedValue 
    = Regex.Replace(value.ToString(), "[^0-9]""");
            
            trimmedValue.Label(label).IsNumeric().WithLengthRange(
    13.To(19));
            var numbers 
    = trimmedValue.Trim().Reverse().Select(c => int.Parse(c.ToString()));
            var oddSum 
    = numbers.AtOddPositions().Sum();
            var doubleEvenSum 
    = numbers.AtEvenPositions().SelectMany(i => new[] { (i * 2% 10, (i * 2/ 10 }).Sum();
            
    //if ((oddSum + doubleEvenSum) % 10 != 0)
            
    //{
            
    //    throw new ValidationException(label,"{0} is not a valid credit card number".With(label));
            
    //}
        }
        
    return this;
    }

        这样,系统在成功提交定单信息之后,就会将详细信息显示出来。
        
            
        
          到这里,用户购买并下单的流流程就走完了,但整个业务流程并没结束,我们还要切换回管理员
    身份去查看并进行相应操作:
        
            
       

         注:此时系统还会对用户的信用卡信息进行有效性校验等。
       
       
         好了,主要的业务流程就介绍到这里了。

         下面简单介绍一下产品的项目文件,该产品共包括四个项目:
         Suteki.Common:该项目包括一些基础的功能类,扩展方法,以及Controller,Model,Filter的
    基类声明(会在以后文章中分别说明),还包括一些Service接口定制,第三方插件扩展。另外还有相
    应的ViewData基类和相关附属类型声明。

         Suteki.Common.Tests:该项目主要是针对上面的Suteki.Common项目的单元测试。
       
         Suteki.Shop:该项目包括对 Controller,Model,Filter等的具体设计和功能实现。Service,
    ViewData具体定义和实现,HtmlHelpers扩展,Repositories(CRUD)封装,Views文件夹等等。

         Suteki.Shop.Tests:该项目主要是针对上面的Suteki.Shop项目的单元测试。
      

         今天的内容就先到这里了。在下篇中,将会介绍一下该项目中的Controller的继承结构和实现方式,
    感兴趣的朋友敬请关注:)
           

         SQL安装脚本下载: http://files.cnblogs.com/daizhj/suteki_Database.rar 
       

         原文链接:http://www.cnblogs.com/daizhj/archive/2009/05/07/1451925.html

         作者: daizhj, 代震军, LaoD

         Tags: mvc,Suteki

         网址: http://daizhj.cnblogs.com/

    [C#]博客园电子期刊

    mikel阅读(910)

    MVP专家区

    .NET技术

    .NET 3.5新技术

    Web开发

    软件工程

    其他

    热点新闻

    [REST]REST构架风格介绍之二:CRUD

    mikel阅读(867)

    上一节我们通过两个例子初步体会了REST状态表述转移的味道,但应该指出这两个例子还仅仅是简单的资源获取。REST是以资源为核心的,没有服务的概念,这的确让人怀疑REST能否像ORBSOA一样支持复杂的应用?在回答这个问题之前,让我们先暂时离开REST,把眼光转向基于关系数据库的3层构架。

    通常业务逻辑层对外提供若干的功能接口(如图中定义的IOrderService),对内通过数据访问层访问数据库。我们知道,关系数据库只定义了CRUD(Create, Read, Update, Delete)四种标准的数据操作,分别对应于insert/select/update/delete四种SQL语句。经验告诉我们,关系数据库在若干张表上进行关系运算是足以支持各种复杂业务逻辑的,因为所有业务功能最终都会被映射到数据库上的CRUD四种标准操作。下面这个有趣的三角形能帮助我们理解这个问题:

    图中的三角分别代表:数据类型、操作、实例。可以把他们想象成可以调节的按钮,业务逻辑层的方式是:定义了少量的服务实例,把大量的操作放在服务实例下面,形象地比喻为“一扇小门,里面装了很多东西”;而数据库的方式则是提供了大量数据实例和CRUD四种标准操作,可比喻为“很多门,每扇门里面装少量的东西”。

    以资源为核心的REST和以数据为核心的关系数据库是类似的。数据和资源本质上都是状态,对状态的操作CRUD少一个不行,多一个多余。因此,REST也采用CRUD四种标准操作,分别对应于HTTP协议的POST/GET/PUT/Delete方法。虽然HTTP协议支持POST/GET/PUT/Delete以外的HEAD等方法,可以把这些非标准方法作为有用的补充,但不应影响REST模型的纯洁性。上一节中,我们看到REST风格的应用像一个状态机;而这里我们则看到它像一个数据库。REST方式定义出的资源(Url)和相应的操作就像下面这个样子(值得重申的是,从Url的含义“统一资源定位符”就可以看出其通用性,这也是REST资源表示的优势所在):

    REST完美地结合了HTTP协议,所以更容易无缝接入互联网。另外,有人提到 “一个网站对外暴露的网页数可以作为衡量它为互联网所做贡献的指标”,如果从这个角度来看,以资源为核心的REST方式比服务为核心的SOA对互联网更加友好。但 应该采用哪种风格的构架还是取决于应用本身的特点,一般来讲,对于以提供和管理数据为主的,且希望做SEO的应用适合REST风格,这包括大多数 WEB2.0的应用;而以计算和业务逻辑为主,且强调安全性的应用不太适合REST风格。但应避免不加分析先入为主的采用面向服务的思维,有时候恰当运用 状态表述转移模式的REST构架不但可以实现业务逻辑,而且具有更好的伸缩性,正如上一节谈到的心理测试服务和Google搜索一样。REST的价值就在 于让我们在设计构架的时候多了一种视角,所谓“眼界决定世界”。

    Cache

    由于RESTUrl表示资源和无状态服务特点,使得Cache机制变得异常简单,且HTTP协议中有直接支持。服务器响应可以通过cache-control:max-age,expires指定资源缓存时间;还可以在响应头的last-modified参数标明资源的最后修改时间,客户端请求可以带上if-modified-since参数,如果资源未过期,服务器只需用返回304 not modified状态即可,这样就避免了服务器端重复工作,也节省网络带宽;etag参数也是常用的cache控制参数,可以解决last-modified时间精度不够的问题。另外,HTTP协议还对Proxy机制有直接的支持,与Cache机制结合,在需要高性能的应用中,可以在服务器与客户端之间部署若干专门用于Cache目的Caching Proxy Server提高系统吞吐量

    总结

    最后总结一下REST的要点:1. Url表示资源;2.  CRUD操作;3. 状态表述转移。至于无状态服务、Http状态码、Cache控制、Proxy等则属于上面几个要点的推论,理解REST的关键还在于理解以资源为核心的模型。本文是我接触REST不到一年时间的一些体会和总结,深知对REST的掌握和应用还需继续努力,希望得到高手的指点!

    相关链接

    1.《如何获取一杯咖啡——星巴克REST案例分析》

    2.《深入浅出REST》

    [Flash]Flash和Flash的通信

    mikel阅读(910)

    转载:http://www.blueidea.com/tech/multimedia/2004/1712_3.asp

    Flash和Flash的通信
    通过上面两种方法的混和使用,同一HTML中两个或者更多的Flash直接可以相互传送消息. 从一个flash使用fscommand传送消息给JavaScript,使用Flash的JavaScript methods把消息传给另外一个flash
    详细的看这里:Flash影片之间的通信示例
    从Flash MX开始,local connection对象可以用来在flash之间传送消息. 这使得同一HTML中的或者位于两个浏览器窗口中的两个flash影片可以相互发送消息,而不必使用Javascript或者fscommand
    详细的看这里:在Flash MX中使用local connection对象(英文)

    本站的localConnection教程:http://www.blueidea.com/tech/multimedia/2003/739.asp
    附可控制Flash Player的Javascript方法:
    一览表:
    Play() —————————————- 播放动画
    StopPlay()————————————停止动画
    IsPlaying()———————————– 动画是否正在播放
    GotoFrame(frame_number)—————- 跳转到某帧
    TotalFrames()——————————- 获取动画总帧数
    CurrentFrame()——————————回传当前动画所在帧数-1
    Rewind()————————————-使动画返回第一帧
    SetZoomRect(left,top,right,buttom)——-放大指定区域
    Zoom(percent)——————————改变动画大小
    Pan(x_position,y_position,unit)————使动画在x,y方向上平移
    PercentLoaded()—————————-返回动画被载入的百分比
    LoadMovie(level_number,path)———– 加载动画
    TGotoFrame(movie_clip,frame_number)- movie_clip跳转到指定帧数
    TGotoLabel(movie_clip,label_name)—— movie_clip跳转到指定标签
    TCurrentFrame(movie_clip)————— 回传movie_clip当前帧-1
    TCurrentLabel(movie_clip)—————–回传movie_clip当前标签
    TPlay(movie_clip)—————————播放movie_clip
    TStopPlay(movie_clip)———————-停止movie_clip的播放
    GetVariable(variable_name)—————–获取变量
    SetVariable(variable_name,value)———–变量赋值
    TCallFrame(movie_clip,frame_number)—call指定帧上的action
    TCallLabel(movie_clip,label)—————-call指定标签上的action
    TGetProperty(movie_clip,property)——–获取movie_clip的指定属性
    TSetProperty(movie_clip,property,number)-设置movie_clip的指定属性

    在 flash mx 以后,由于一系列的安全问题,比如载入另一个站点的 flash文件,然后用javascript控制 flash 跳转到不同的帧,让一些 flash 编写者在安全防范上防不胜防。为此 macromedia 改进了 flash player 和一些交互接口。引入了安全沙箱的概念,也就是可以设置一个可以进行控制的站点列表。

    当然在同一个域名下,可以不考虑这个安全沙箱的问题。

    更详细的接口和用法还有安全限制,请查看下面的PDF文件

    另外我再提供一个 flash4 时代最顶尖的闪客 Dean 利用 javascript 和 flash进行交互的例子,这可是当时,最最眩目的页面了,html和flash结合紧密,而且保证了和 netscape 的兼容。

    点击查看 看看我们4年前的闪客,在做什么?

    另外,我在今年也有类似的应用,大家可以查看 bt 的专栏动画部分 ,在打开一个flash动画弹出框时,为了不影响音乐杂乱,我关闭了主场景的音乐开关。关闭弹出框时,打开主场景的音乐开关,这点,也主要是依靠 javascript 来进行对 flash 的控制的。

    出处:蓝色理想
    责任编辑:qhwa

    [Flash]Flash到Javascript的通信

    mikel阅读(685)

    Flash到JavaScript的通信
    从HTML可以发送数据到Flash,反过来也可以. 这个例子演示了如何应用Flash的Fscommand来发送数据到JavaScript.

    查看示例:示例2
    下载源文件: flash_to_javascript.zip(10K)
    简要步骤:
    Flash中
    新建一个文件,保存为flash_to_javascript.fla
    创建一个文本域,设置成输入文本(Input Text),选择"border"以便我们能看到他,指定他的变量为inputVar
    创建一个按钮,在按钮上添加如下的as:

    on (release) {
      fscommand ("send_var", inputVar);
    }

    保存文件,导出HTML和SWF
    Dreamweaver中
    1.打开导出HTML文件,修改<OBJECT>和<EMBED>标签,结果同上:
    <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
    codebase="http://download.macromedia.com/pub/shockwave/cabs/
    flash/swflash.cab#version=5,0,0,0"
    width=366 height=142 id="myFlash">
    <embed src="javascript_to_flash.swf" quality=high
    width=366 height=142
    type="application/x-shockwave-flash"
    pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?
    P1_Prod_Version=ShockwaveFlash" name="myFlash" swLiveConnect="true">
    </embed>

     2. 插入如下的Javascript到<Body>标签内:
    <SCRIPT LANGUAGE=JavaScript>
    <!–
    var InternetExplorer = navigator.appName.indexOf("Microsoft") != -1;
    function myFlash_DoFSCommand(command, args)                {
      var myFlashObj = InternetExplorer ? myFlash : document.myFlash;
      alert (args);
    }

    if (navigator.appName && navigator.appName.indexOf("Microsoft") != -1 &&
      navigator.userAgent.indexOf("Windows") != -1 && navigator.userAgent.indexOf("Windows 3.1") == -1) {
      document.write('<SCRIPT LANGUAGE=VBScript\> \n');
      document.write('on error resume next \n');
      document.write('Sub myFlash_FSCommand(ByVal command, ByVal args)\n');
      document.write(' call myFlash_DoFSCommand(command, args)\n');
      document.write('end sub\n');
      document.write('</SCRIPT\> \n');
    }
    //–>
    </SCRIPT>

    出处:蓝色理想
    责任编辑:qhwa