ASP.NETMVC的篩選器詳細(xì)介紹-創(chuàng)新互聯(lián)

這篇文章主要講解了“ASP.NET MVC的篩選器詳細(xì)介紹”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“ASP.NET MVC的篩選器詳細(xì)介紹”吧!

創(chuàng)新互聯(lián)公司技術(shù)團(tuán)隊(duì)十年來(lái)致力于為客戶提供成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)、成都品牌網(wǎng)站建設(shè)、營(yíng)銷型網(wǎng)站、搜索引擎SEO優(yōu)化等服務(wù)。經(jīng)過(guò)多年發(fā)展,公司擁有經(jīng)驗(yàn)豐富的技術(shù)團(tuán)隊(duì),先后服務(wù)、推廣了成百上千網(wǎng)站,包括各類中小企業(yè)、企事單位、高校等機(jī)構(gòu)單位。

目錄

一、Filter

二、FilterProvider

三、FilterAttribute與FilterAttributeFilterProvider

四、Controller與ControllerInstanceFilterProvider

五、GlobalFilterCollection

六、實(shí)例演示:驗(yàn)證Filter的提供機(jī)制和執(zhí)行順序

一、Filter

雖然ASP.NET MVC提供的四種類型的篩選器具有各自實(shí)現(xiàn)的接口,但是對(duì)于篩選器的提供體系來(lái)說(shuō)所有的篩選器都通過(guò)具有如下定義的Filter類型表示。Filter的核心是Instance屬性,因?yàn)樗碚嬲龑?shí)施篩選功能的對(duì)象,該對(duì)象實(shí)現(xiàn)了一個(gè)或者多個(gè)基于上述四種篩選器類型的接口。

  public class Filter
  {  
    public const int DefaultOrder = -1;  
    public Filter(object instance, FilterScope scope, int? order);
    
    public object Instance { get; protected set; }
    public int Order { get; protected set; }
    public FilterScope Scope { get; protected set; }
  }
  public enum FilterScope
  {
    Action    = 30,
    Controller  = 20,
    First     = 0,
    Global    = 10,
    Last     = 100
  }

注:由于System.Web.Mvc.Filter和實(shí)現(xiàn)了IAuthorizationFilter、IActionFilter、IResultFilter和IExceptionFilter的類型均可以被稱為“篩選器”,為了不至于造成混淆,在沒(méi)有做明確說(shuō)明的情況下,我們使用英文“Filter”和中文“篩選器”分別來(lái)表示它們。

Filter的Order和Scope屬性最終決定了篩選器的執(zhí)行順序。Order屬性對(duì)應(yīng)數(shù)值越小,執(zhí)行的優(yōu)先級(jí)越高,該屬性的默認(rèn)值為-1(對(duì)應(yīng)著Filter中定義的常量DefaultOrder)。如果兩個(gè)Filter具有相同的Order屬性值,那么Scope屬性最終決定哪個(gè)被優(yōu)先執(zhí)行。Filter的Scope屬性類型是一個(gè)類型為FilterScope的枚舉。該枚舉表示應(yīng)用Filter的范圍,Action和Controller代表Action方法和Controller類級(jí)別;First和Last意味著希望被作為第一個(gè)和最后一個(gè)Filter來(lái)執(zhí)行;Global代表一個(gè)全局的Filter。

通過(guò)上面的代碼片斷我們可以看到FilterScope的5個(gè)枚舉選項(xiàng)均被設(shè)置了一個(gè)值,這個(gè)值決定了Filter的執(zhí)行順序,具有更小的枚舉值會(huì)被優(yōu)先執(zhí)行。從FilterScope的定義可以得到這樣的結(jié)論:對(duì)于具有相同Order屬性值的多個(gè)Filter,應(yīng)用在Controller上的Filter比應(yīng)用在Action方法上的Filter具有更高的執(zhí)行優(yōu)先級(jí),而一個(gè)全局的Filter的執(zhí)行優(yōu)先級(jí)又高于基于Action的Filter。

二、FilterProvider

Filter的提供機(jī)制與之前我們介紹的基于ModelBinder和ModelValidator的提供機(jī)制比較類似,均是通過(guò)相應(yīng)的Provider來(lái)提供的。提供篩選器的FilterProvider實(shí)現(xiàn)了接口IFilterProvider,如下面的代碼片斷所示,該接口定義了的方法GetFilters根據(jù)指定的Controller上下文和用于描述目標(biāo)Action的ActionDescriptor對(duì)象獲取一個(gè)Filter對(duì)象集合。

  public interface IFilterProvider
  {  
    IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
  }

我們可以通過(guò)靜態(tài)類型FilterProviders注冊(cè)或者獲取當(dāng)前應(yīng)用使用的FilterProvider。如下面的代碼片斷所示,F(xiàn)ilterProviders具有一個(gè)類型為FilterProviderCollection的只讀屬性Providers,表示基于整個(gè)Web應(yīng)用范圍內(nèi)被使用的FilterProvider列表。FilterProviderCollection是元素類型為IFilterProvider的集合,GetFilters方法用于或者該集合中所有FilterProvider對(duì)象提供的Filter對(duì)象。

  public static class FilterProviders
  {  
    public static FilterProviderCollection Providers { get; }
  } 
  public class FilterProviderCollection : Collection<IFilterProvider>
  {   
    //其他成員
    public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor);  
  }

ASP.NET MVC提供了三種原生的FilterProvider,分別是FilterAttributeFilterProvider、ControllerInstanceFilterProvider和GlobalFilterCollection,接下來(lái)我們對(duì)它們進(jìn)行單獨(dú)介紹。

三、FilterAttribute與FilterAttributeFilterProvider

我們通常將篩選器定義成特性以聲明的方式應(yīng)用到Controller類型或者Action方法上,而抽象類型FilterAttribute是所有篩選器的基類。如下面的代碼片斷所示,F(xiàn)ilterAttribute特性實(shí)現(xiàn)了IMvcFilter接口,該接口定義了Order和AllowMultiple兩個(gè)只讀屬性,分別用于控制篩選器的執(zhí)行順序以及多個(gè)同類的篩選器能夠同時(shí)應(yīng)用到同一個(gè)目標(biāo)元素(類或者方法)。

  [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited=true, AllowMultiple=false)]
  public abstract class FilterAttribute : Attribute, IMvcFilter
  {  
    protected FilterAttribute();
    
    public bool AllowMultiple { get; }
    public int Order { get; set; }
  }
  public interface IMvcFilter
  {  
    bool AllowMultiple { get; }
    int Order { get; }
  }

從應(yīng)用在FilterAttribute上的AttributeUsageAttribute的定義可以看出該特性可以應(yīng)用在類型和方法上,這意味著篩選器一般都可以應(yīng)用在Controller類型和Action方法上。只讀屬性AllowMultiple實(shí)際上返回的是AttributeUsageAttribute的同名屬性,通過(guò)上面的定義我們可以看到默認(rèn)情況下該屬性值為False。

用于描述Controller和Action的ControllerDescriptor和ActionDescriptor均實(shí)現(xiàn)了ICustomAttributeProvider接口,我們可以直接利用它們獲取應(yīng)用在對(duì)應(yīng)的Controller類型或者Action方法上包括FilterAttribute在內(nèi)的所有特性。實(shí)際上,這兩個(gè)描述類型提供了單獨(dú)的方法GetFilterAttributes專門用于獲取FilterAttribute特性列表。如下面的代碼片斷所示,該方法具有一個(gè)布爾類型的參數(shù)useCache,表示是否需要對(duì)解析出來(lái)的FilterAttribute特性進(jìn)行緩存以緩解頻繁的反射操作對(duì)性能造成的影響。

  public abstract class ControllerDescriptor : ICustomAttributeProvider, IUniquelyIdentifiable
  {
    //其他成員
    public virtual IEnumerable<FilterAttribute> GetFilterAttributes(bool useCache);
  }
  public abstract class ActionDescriptor : ICustomAttributeProvider, IUniquelyIdentifiable
  {  
    //其他成員
    public virtual IEnumerable<FilterAttribute> GetFilterAttributes(bool useCache);  
  }

針對(duì)FilterAttribute特性的Filter通過(guò)FilterAttributeFilterProvider對(duì)象來(lái)提供。FilterAttributeFilterProvider直接調(diào)用當(dāng)前ControllerDescriptor和ActionDescriptor的GetFilterAttributes方法獲取所有應(yīng)用在Controller類型和當(dāng)前Action方法的FilterAttribute特性,并借此創(chuàng)建相應(yīng)的Filter對(duì)象。FilterAttributeFilterProvider構(gòu)造函數(shù)的參數(shù)cacheAttributeInstances表示是否啟用針對(duì)FilterAttribute的緩存,它將作為調(diào)用GetFilterAttributes方法的參數(shù)。在默認(rèn)的情況下(通過(guò)調(diào)用默認(rèn)無(wú)參的構(gòu)造函數(shù)創(chuàng)建的FilterAttributeFilterProvider)會(huì)采用針對(duì)FilterAttribute的緩存。

  public class FilterAttributeFilterProvider : IFilterProvider
  {
    public FilterAttributeFilterProvider();
    public FilterAttributeFilterProvider(bool cacheAttributeInstances);
    protected virtual IEnumerable<FilterAttribute> GetActionAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
    protected virtual IEnumerable<FilterAttribute> GetControllerAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
    public virtual IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
  }

對(duì)于通過(guò)調(diào)用GetFilters得到的Filter,對(duì)應(yīng)的FilterAttribute特性作為其Instance屬性。Order屬性來(lái)源于FilterAttribute的同名屬性,而Scope屬性則取決于FilterAttribute特性是應(yīng)用在Controller類型上(Scope屬性值為Controller)還是當(dāng)前的Action方法上(Scope屬性值為Action)。

四、Controller與ControllerInstanceFilterProvider

提到ASP.NET MVC的篩選器,大部分的都只會(huì)想到通過(guò)FilterAttribute特性,實(shí)際上Controller本身(繼承自抽象類Controller)就是一個(gè)篩選器。如下面的代碼片斷所示,抽象類Controller實(shí)現(xiàn)了IActionFilter、IAuthorizationFilter、IExceptionFilter和IResultFilter這四個(gè)對(duì)應(yīng)著不同篩選器類型的接口。

  public abstract class Controller : ControllerBase, 
    IActionFilter, 
    IAuthorizationFilter, 
    IExceptionFilter, 
    IResultFilter, 
     ...
  {
    //省略成員
  }

針對(duì)Controller對(duì)象這種獨(dú)特篩選器的FilterProvider類型為具有如下定義的ControllerInstanceFilterProvider。在實(shí)現(xiàn)的GetFilters方法中,它會(huì)根據(jù)指定的Controller上下文獲取對(duì)應(yīng)的Controller對(duì)象,并以此創(chuàng)建一個(gè)Filter(Controller對(duì)象作為Filter對(duì)象的Instance屬性值)。該Filter的Scope不是Controller,而是First,而Order的值為-2147483648(Int32.MinValue),毫無(wú)疑問(wèn)這樣的Filter肯定第一個(gè)被執(zhí)行。

  public class ControllerInstanceFilterProvider : IFilterProvider
  {  
    public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor);  
  }

五、GlobalFilterCollection

通過(guò)FilterAttribute的形式定義的篩選器需要顯式地標(biāo)注到目標(biāo)Controller類型或者Action方法上,而在有些情況下需要一種全局的Filter。所謂全局篩選器,就是不需要顯式與某個(gè)Controller或者Action進(jìn)行匹配,而是默認(rèn)使用到所有的Action執(zhí)行過(guò)程中。用于提供這種全局Filter的FilterProvider對(duì)應(yīng)的類型為具有如下定義的GlobalFilterCollection。

  public sealed class GlobalFilterCollection : IEnumerable<Filter>, IEnumerable, IFilterProvider
  {
    public GlobalFilterCollection();
    public void Add(object filter);
    public void Add(object filter, int order);
    private void AddInternal(object filter, int? order);
    public void Clear();
    public bool Contains(object filter);
    public IEnumerator<Filter> GetEnumerator();
    public void Remove(object filter);
    IEnumerator IEnumerable.GetEnumerator();
    IEnumerable<Filter> IFilterProvider.GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
    public int Count { get; }
  }

通過(guò)命名以及上面給出的定義可以看出GlobalFilterCollection就是一個(gè)Filter的列表而已,實(shí)現(xiàn)的GetFilters方法返回的就是它自己。通過(guò)GlobalFilterCollection提供的方法我們可以實(shí)現(xiàn)對(duì)全局Filter的添加、刪除和清除操作。用于添加Filter的Add方法的參數(shù)filter不是一個(gè)Filter對(duì)象,而是一個(gè)具體篩選器(實(shí)現(xiàn)了相應(yīng)的篩選器接口),添加的Filter對(duì)象根據(jù)該篩選器對(duì)象創(chuàng)建,其Scope屬性被設(shè)置成Global。我們通過(guò)在Add方法指定添加Filter對(duì)象的Order屬性,如果沒(méi)有顯示指定Order并且指定的篩選器是一個(gè)FilterAttribute特性,那么該特性的Order將會(huì)作為Filter對(duì)象的Order;否則使用-1作為Order屬性值。

針對(duì)整個(gè)Web應(yīng)用的全局Filter(或者說(shuō)全局FilterProvider)的注冊(cè)和獲取可以通過(guò)靜態(tài)類型GlobalFilters來(lái)實(shí)現(xiàn)。如下面的代碼片斷所示,GlobalFilters具有一個(gè)靜態(tài)只讀屬性Filters返回一個(gè)GlobalFilterCollection對(duì)象。

  public static class GlobalFilters
  {  
    public static GlobalFilterCollection Filters { get; }
  }

到目前為止,我們已經(jīng)介紹了ASP.NET MVC默認(rèn)提供的三種FilterProvider,以及各自采用得Filter提供機(jī)制。當(dāng)用于注冊(cè)FilterProvider的靜態(tài)類型在加載的時(shí)候,會(huì)默認(rèn)創(chuàng)建這三種類型的對(duì)象并將其作為表示全局FilterProvider集合的Providers屬性值,具體的邏輯體現(xiàn)在如下的代碼片斷中。也就是說(shuō),在默認(rèn)的情況下ASP.NET MVC會(huì)采用這三種FilterProvider來(lái)提供所有的Filter對(duì)象。

  public static class FilterProviders
  { 
    static FilterProviders()
    {
      Providers = new FilterProviderCollection();
      Providers.Add(GlobalFilters.Filters);
      Providers.Add(new FilterAttributeFilterProvider());
      Providers.Add(new ControllerInstanceFilterProvider());
    } 
    public static FilterProviderCollection Providers{get;private set;}
  }

六、實(shí)例演示:驗(yàn)證Filter的提供機(jī)制和執(zhí)行順序

為了讓讀者對(duì)上面介紹的Filter提供機(jī)制具有一個(gè)更加深刻的映像,我們來(lái)做一個(gè)簡(jiǎn)單的實(shí)例演示。在一個(gè)通過(guò)Visual Studio的ASP.NET MVC項(xiàng)目模板創(chuàng)建的空Web項(xiàng)目中,我們定義了如下一個(gè)幾個(gè)FilterAttribute。FilterBaseAttribute是一個(gè)實(shí)現(xiàn)了IActionFilter接口的抽象類型,三個(gè)具體的FilterAttribute(FooAttribute、BarAttribute和BazAttribute)是它的繼承者。

  public abstract class FilterBaseAttribute:FilterAttribute, IActionFilter
  {
    public void OnActionExecuted(ActionExecutedContext filterContext)
    {} 
    public void OnActionExecuting(ActionExecutingContext filterContext)
    {}
  } 
  public class FooAttribute : FilterBaseAttribute
  {}
  public class BarAttribute : FilterBaseAttribute
  {}
  public class BazAttribute : FilterBaseAttribute
  {}

我們首先在Global.asax中通過(guò)如下的方式將BazAttribute注冊(cè)為一個(gè)全局篩選器。需要注意的是定義在默認(rèn)創(chuàng)建的Global.asax中的Application_Start方法會(huì)調(diào)用RegisterGlobalFilters方法注冊(cè)一個(gè)類型為HandleErrorAttribute的ExceptionFilter,我們需要將這行代碼注釋。

  public class MvcApplication : System.Web.HttpApplication
  {
    //其他成員
    protected void Application_Start()
    {    
      //其他操作
      //RegisterGlobalFilters(GlobalFilters.Filters);    
      GlobalFilters.Filters.Add(new BazAttribute());
    }
  }

最后我們創(chuàng)建如下一個(gè)默認(rèn)的HomeController,一個(gè)空的Action方法Data上應(yīng)用了我們定義的BarAttribute特性,而HomeController類上則應(yīng)用了FooAttribute特性。在默認(rèn)的Action方法Index中,我們通過(guò)FilterProviders的靜態(tài)屬性Providers表示的全局FilterProvider列表得到針對(duì)于Action方法Data的所有Filter對(duì)象,并將它們的基本信息(類型、Order和Scope屬性)呈現(xiàn)出來(lái)。

  [Foo]
  public class HomeController : Controller
  {
    public void Index()
    {
      ReflectedControllerDescriptor controllerDescriptor = new ReflectedControllerDescriptor(typeof(HomeController));
      ActionDescriptor actionDescriptor = controllerDescriptor.FindAction(ControllerContext, "Data");
      foreach (var filter in FilterProviders.Providers.GetFilters(ControllerContext, actionDescriptor))
      { 
        Response.Write(string.Format("{0}<br/>",filter.Instance));
        Response.Write(string.Format("&nbsp;&nbsp;&nbsp;&nbsp;{0}: {1}<br/>", "Order",filter.Order));
        Response.Write(string.Format("&nbsp;&nbsp;&nbsp;&nbsp;{0}: {1}<br/><br/>", "Scope",filter.Scope));
      }
    }
    [Bar]
    public void Data()
    { }
  }

運(yùn)行我們的程序之后會(huì)在瀏覽器中呈現(xiàn)如圖7-5所示的結(jié)果。我們可以清楚地看到,不僅僅應(yīng)用在自身Action方法的FilterAttribute會(huì)應(yīng)用到目標(biāo)Action上,應(yīng)用在Controller類的FilterAttribute、全局注冊(cè)的Filter以及Controller對(duì)象本身體現(xiàn)的Filter都回最終應(yīng)用在所有的Action上面。

ASP.NET MVC的篩選器詳細(xì)介紹

上圖將應(yīng)用于Action方法Data的4個(gè)Filter的Order和Scope屬性顯示出來(lái)。我們?cè)谇懊嫣岬竭@兩個(gè)屬性決定了同類篩選器執(zhí)行的順序,我們現(xiàn)在利用這個(gè)程序要證實(shí)這一點(diǎn)。為此我們需要對(duì)FilterBaseAttribute作如下的修改,在OnActionExecuting中我們將當(dāng)前執(zhí)行的FilterAttribute的類型的方法名呈現(xiàn)出來(lái)。

  public abstract class FilterBaseAttribute:FilterAttribute, IActionFilter
  {
    public void OnActionExecuted(ActionExecutedContext filterContext)
    {}
    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
      filterContext.HttpContext.Response.Write(string.Format("{0}.OnActionExecuting()<br/>", this.GetType()));
    }
  }

然后我們按照相同的方式重寫了HomeController的OnActionExecuting方法,將HomeController自身的類型的當(dāng)前方法名稱呈現(xiàn)出來(lái)。

  [Foo]
  public class HomeController : Controller
  {
    //其他成員
    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
      Response.Write("HomeController.OnActionExecuting()<br/>");
    } 
    [Bar]
    public void Data()
    { }
  }

我們?cè)俅芜\(yùn)行我們的程序,并在瀏覽器上指定正確的地址訪問(wèn)定義在HomeController的Action方法Data,會(huì)在瀏覽器中呈現(xiàn)如下圖所示的結(jié)果。輸出的結(jié)果體現(xiàn)了應(yīng)用到Action方法Data上的四個(gè)ActionFilter執(zhí)行的順序,而這是和Filter對(duì)應(yīng)的Order和Scope屬性值是一致的。

ASP.NET MVC的篩選器詳細(xì)介紹

關(guān)于Filter的提供還另一個(gè)值得深究的問(wèn)題:我們?cè)诙xFilterAttribute的時(shí)候可以將應(yīng)用在該類型上的AttributeUsageAttribute的AllowMultiple屬性設(shè)置為False使它只能在同一個(gè)目標(biāo)元素上應(yīng)用一次。但是,我們依然可以在Action方法和所在的Controller類型上應(yīng)用它們,甚至可以將它們注冊(cè)為全局Filter,那么這些FilterAttribute都將有效嗎?

我們現(xiàn)在就來(lái)通過(guò)實(shí)例來(lái)驗(yàn)證這一點(diǎn)?,F(xiàn)在我們刪除所有的FilterAttribute,定義如下一個(gè)類型為FooAttribute的ActionFilter,我們將應(yīng)用在它上面的AttributeUsageAttribute特性的AllowMultiple屬性設(shè)置為False。

  [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
  public class FooAttribute : FilterAttribute, IActionFilter
  {
    public void OnActionExecuted(ActionExecutedContext filterContext)
    { }
    public void OnActionExecuting(ActionExecutingContext filterContext)
    { }
  }

現(xiàn)在我們將該FooAttribute特性同時(shí)應(yīng)用在HomeController類型和Action方法Data上,然后在Global.asax中注冊(cè)一個(gè)針對(duì)FooAttribute特性的全局Filter。

  [Foo]
  public class HomeController : Controller
  {
    //其他成員
    [Foo]
    public void Data()
    { }
  } 
  public class MvcApplication : System.Web.HttpApplication
  {
    //其他成員
    protected void Application_Start()
    {
      //其他操作
      //RegisterGlobalFilters(GlobalFilters.Filters);
      GlobalFilters.Filters.Add(new FooAttribute());
    }
  }

現(xiàn)在我們直接運(yùn)行我們的程序,開(kāi)啟的瀏覽器中會(huì)呈現(xiàn)出如圖7-7所示的結(jié)果。可以清楚地看到雖然我們 在三個(gè)地方注冊(cè)了FooAttribute,但是由于該特性的AllowMultiple屬性為False,所以只有其中一個(gè)FooAttribute最終是有效的。

ASP.NET MVC的篩選器詳細(xì)介紹

對(duì)于AllowMultiple屬性為False的FilterAttribute來(lái)說(shuō),如果我們以不同的Scope注冊(cè)了多個(gè),最終有效的是哪個(gè)呢?從上圖可以看出,應(yīng)用在Action方法(Scope為Action)上的FooAttribute是有效的。其實(shí)具體的邏輯是這樣的:所有被創(chuàng)建的Filter按照Order+Scope進(jìn)行排序(即Filter執(zhí)行的順序),取排在最后一個(gè)。對(duì)于我們的例子來(lái)說(shuō),提供的三個(gè)Filter具有相同的Order屬性值(-1),所有最終會(huì)按照Scope(Scope、Controller和Action)進(jìn)行排序,排在最后一個(gè)的自然是Scope為Action的Filter。

感謝各位的閱讀,以上就是“ASP.NET MVC的篩選器詳細(xì)介紹”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)ASP.NET MVC的篩選器詳細(xì)介紹這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司,,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

分享名稱:ASP.NETMVC的篩選器詳細(xì)介紹-創(chuàng)新互聯(lián)
瀏覽地址:http://bm7419.com/article30/gdcso.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站營(yíng)銷、靜態(tài)網(wǎng)站、App設(shè)計(jì)、網(wǎng)站排名、服務(wù)器托管、網(wǎng)站設(shè)計(jì)公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)