为什么要使用接口?

为什么要使用接口?而不直接使用类呢?

*:first-child {
margin-top: 0 !important;
}

body>*:last-child {
margin-bottom: 0 !important;
}

/* BLOCKS
=============================================================================*/

p, blockquote, ul, ol, dl, table, pre {
margin: 15px 0;
font-family: microsoft yahei,宋体;
}

/* HEADERS
=============================================================================*/

h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
}

h1 tt, h1 code, h2 tt, h2 code, h3 tt, h3 code, h4 tt, h4 code, h5 tt, h5 code, h6 tt, h6 code {
font-size: inherit;
}

h1 {
font-size: 28px;
color: #000;
background-color:#CDCDCD;
}

h2 {
font-size: 24px;
border-bottom: 1px solid #ccc;
color:white;
background-color: #167A33;
text-indent: 0.25em;
border-radius: 0.5em;
}

h3 {
font-size: 18px;
background-color: #6CA7A7;
color: white;
border-radius: 0.5em;
text-indent: 0.25em;
}

h4 {
font-size: 16px;
}

h5 {
font-size: 14px;
}

h6 {
color: #777;
font-size: 14px;
}

body>h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child {
margin-top: 0;
padding-top: 0;
}

a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0;
}

h1+p, h2+p, h3+p, h4+p, h5+p, h6+p {
margin-top: 10px;
}

/* LINKS
=============================================================================*/

a {
color: #4183C4;
text-decoration: none;
}

a:hover {
text-decoration: underline;
}

/* LISTS
=============================================================================*/

ul, ol {
padding-left: 30px;
}

ul li > :first-child,
ol li > :first-child,
ul li ul:first-of-type,
ol li ol:first-of-type,
ul li ol:first-of-type,
ol li ul:first-of-type {
margin-top: 0px;
}

ul ul, ul ol, ol ol, ol ul {
margin-bottom: 0;
}

dl {
padding: 0;
}

dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px;
}

dl dt:first-child {
padding: 0;
}

dl dt>:first-child {
margin-top: 0px;
}

dl dt>:last-child {
margin-bottom: 0px;
}

dl dd {
margin: 0 0 15px;
padding: 0 15px;
}

dl dd>:first-child {
margin-top: 0px;
}

dl dd>:last-child {
margin-bottom: 0px;
}

/* CODE
=============================================================================*/

pre, code, tt {
font-size: 12px;
font-family: Consolas, "Liberation Mono", Courier, monospace;
}

code, tt {
margin: 0 0px;
padding: 0px 0px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px;
}

pre>code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent;
}

pre {
background-color: #f8f8f8;
border: 1px solid #ccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px;
}

pre code, pre tt {
background-color: transparent;
border: none;
}

kbd {
-moz-border-bottom-colors: none;
-moz-border-left-colors: none;
-moz-border-right-colors: none;
-moz-border-top-colors: none;
background-color: #DDDDDD;
background-image: linear-gradient(#F1F1F1, #DDDDDD);
background-repeat: repeat-x;
border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD;
border-image: none;
border-radius: 2px 2px 2px 2px;
border-style: solid;
border-width: 1px;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
line-height: 10px;
padding: 1px 4px;
}

/* QUOTES
=============================================================================*/

blockquote {
border-left: 4px solid #DDD;
padding: 0 15px;
color: #777;
}

blockquote>:first-child {
margin-top: 0px;
}

blockquote>:last-child {
margin-bottom: 0px;
}

/* HORIZONTAL RULES
=============================================================================*/

hr {
clear: both;
margin: 15px 0;
height: 0px;
overflow: hidden;
border: none;
background: transparent;
border-bottom: 4px solid #ddd;
padding: 0;
}

/* TABLES
=============================================================================*/

table {
font-family: verdana,arial,sans-serif;
font-size:11px;
color:#333333;
border-width: 1px;
border-color: #999999;
border-collapse: collapse;
width:80%;
margin:auto;
}

table th {
background-color:rgb(111, 182, 45);
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #a9c6c9;
font-family: microsoft yahei,宋体;
font-size:18px;
}
table tr {
background-color:#d4e3e5;
}
table td {
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #a9c6c9;
font-family: microsoft yahei,宋体;
font-size:14px;
}

table tr:nth-child(2n) {
background-color: #DDDDDD;
}

/* IMAGES
=============================================================================*/

img {
max-width: 100%
}
-->

1 什么是接口?

  • 接口是一种用来定义程序的协议,它描述可属于任何类或结构的一组相关行为。
    接口是一组规则的集合,它规定了实现本接口的类或接口必须拥有的一组规则。体现了自然界“如果你是……则必须能……”的理念。
    接口是在一定粒度视图上同类事物的抽象表示。因为“同类事物”这个概念是相对的,它因为粒度视图不同而不同。

2 为什么要使用接口?而不是直接实现呢?

接口的使用并非总是从设计的角度来考虑。接口和C#其他语法现象一样,共同构成了C#整个语言体系。
接口的意义在于 抽象、不拘细节,从而使同类事物在同一高度具有通用及可替代性。
关于解耦,并不是接口能解耦,而是抽象能解耦 接口只是手段,如果两个事物有必然联系,那么就不会出现完全解耦,只能耦合转移。
                                                                                —— from http://bbs.csdn.net/topics/380040137

在系统分析和架构中,分清层次和依赖关系,每个层次不是直接向其上层提供服务(即不是直接实例化在上层中),而是通过定义一组接口,仅向上层暴露其接口功能,上层对于下层仅仅是接口依赖,而不依赖具体类。

  • 系统灵活性增强

当下层需要改变时,只要接口及接口功能不变,则上层不用做任何修改。甚至可以在不改动上层代码时将下层整个替换掉,就像我们将一个WD的60G硬盘换成一个希捷的160G的硬盘,计算机其他地方不用做任何改动,而是把原硬盘拔下来、新硬盘插上就行了,因为计算机其他部分不依赖具体硬盘,而只依赖一个IDE接口,只要硬盘实现了这个接口,就可以替换上去。

  • 不同部件或层次的开发人员可以并行开工

就像造硬盘的不用等造CPU的,也不用等造显示器的,只要接口一致,设计合理,完全可以并行进行开发,从而提高效率。

那么具体什么时候用,什么时候不用呢?在常见的三层架构中,有以下几个层次,分别进行说明:

  • 界面层

也就是展示层,直接呈现给用户的,可能不同的软件有不同的呈现方式,比如Web,WinForm,甚至移动APP,在这个层次,我认为是没有必要写太多的接口。

  • 业务逻辑层

这个层次,业务逻辑,可以根据需要使用接口。如果是直接读写数据库什么的,就直接用调用数据库访问层的接口。如果是与多个第三方接口进行交互,那么就需要接口,不同的渠道各自实现。

  • 数据访问层

数据访问层,最好使用接口,比如数据库访问,这种可以根据不同的数据库实现相应的接口向业务逻辑层提供服务。

可能在开发的时候,一开始我们并没有想到要使用接口。可能简单就用一个类实现了。到后面新的需求过来的时候,发现代码需要重构,要用接口和抽象类等等。这个也需要看个人编码的习惯。有的人就长篇大论一个类完成所有的逻辑。这样的开发人员,应该是很少见过好的代码,如果见过的话,后面肯定会精简做到更好。而另外一些人可能一开始就能嗅出来哪些地方需要使用接口,哪些地方使用抽象类,这也是一种思维方式。前面一种只管开发当前的功能。而后面一种则会考虑到以后的扩展。总而言之,需要根据不同的情况进行考虑。

2.1 面向接口编程

面向接口编程:面向接口编程和面向对象编程并不是平级的,它并不是比面向对象编程更先进的一种独立的编程思想,而是附属于面向对象思想体系,属于其一部分。或者说,它是面向对象编程体系中的思想精髓之一.

2.2 软件设计中有关接口的原则

我一直认为这个问题,应该从设计的角度来讲。在软件设计的六大设计原则中,与接口直接相关的就有以下两个:

  • 依赖倒置原则

高层模块不应该依赖底层模块,二则都应该依赖其抽象,抽象不应该依赖细节;细节应该依赖抽象。
问题由来:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。
解决方案:面向接口编程,将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。

  • 接口隔离原则

定义:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
问题由来:类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和类B来说不是最小接口,则类B和类D必须去实现他们不需要的方法。
解决方案:在设计接口的时候要精简单一,将臃肿的接口I拆分为独立的几个接口,类A和类C分别与他们需要的接口建立依赖关系。也就是采用接口隔离原则。

  • 总结

单一职责原则告诉我们实现类要职责单一;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合。而开闭原则是总纲,他告诉我们要对扩展开放,对修改关闭。接口在设计模式中,有很多的灵活应用。

2.3 我所遇到的使用接口的场景

  • WCF服务的契约就是接口
  • 数据库访问层

定义数据库访问层的接口,然后不同的数据库类型(MySQL/SQL Server)实现不同的接口,向业务层提供服务。这样如果说从SQL Server数据库迁移到MySQL数据库,业务层几乎不需要怎么改动,直接用MySQL的进行访问就可以了。
在数据访问接口层的参数通常都是IDbConnection这样的接口,而不是具体的类。体现了,依赖倒置原则。

3 接口和抽象类有什么不同?

这个主要是以C#语言为基础来讲的。

3.1 相同点

  • 都可以被继承
  • 都不能被实例化
  • 都可以包含方法声明
  • 派生类必须实现未实现的方法

3.2 区别

  • 语法上
接口 抽象类
接口只能定义属性、索引器、事件、和方法声明,没有普通成员变量 抽象类没有此限制
接口不能有构造方法(这简直是废话) 抽象类可以有构造方法
接口中的所有方法必须都是抽象的 抽象类中可以包含非抽象的普通方法
接口中的方法只能是public类型的(默认) 抽象类中的抽象方法的访问类型可以是public,protected
接口可以用于支持回调 而继承并不具备这个特点
实现接口的类中的接口方法却默认为非虚的,(实现类的派生类,不可以再重写实现类接口方法,但派生类可以再显示实现接口的方法)
实现接口的类中的接口方法可以声明为virtual(这样实现类的派生类还可以重写该方法).
抽象类实现的具体方法默认为虚的
  • 其他方面
接口 抽象类
接口是一个行为规范 抽象类是一个不完整的类,需要进一步细化
接口可以被多重实现 抽象类只能被单一继承
接口大多数是关系疏松但都实现某一功能的类中 抽象类更多的是定义在一系列紧密相关的类间
接口是为了满足外部调用而定义的一个功能约定, 因此反映的是事物的外部特性 抽象类是从一系列相关对象中抽象出来的概念, 因此反映的是事物的内部共性

4 使用接口还是抽象类?

4.1 IS A VS CAN-DO 关系

  • IS A 关系用抽象类

一般到具体的这样一个关系,就用抽象。
逻辑相关,并且有相同的功能的可以使用抽象类,不用每个接口都去写。

  • CAN DO 关系用接口,值类型用接口

接口是对同类事物的横切面的一个抽象。体现能的逻辑关系。在设计接口的时候,依据接口隔离原则,接口的方法都是必须的,最少的。实现类如果要使用一个接口,那么它必须实现接口的所有方法。即全都能。

    • 接口和抽象类可以同时使用。

两件事情实际上可以同时做:定义一个接口,同时提供一个实现了这个接口的基类。

4.2 易于使用

  • 定义一个从基类派生的新类型通常比实现一个接口的所有方法容易得多。基类型可以提供大量功能,所以派生类可能只需要针对其行为稍作改动。
  • 使用接口,则新类型必须实现所有的成员。

4.3 版本控制

  • 向基类添加一个方法,派生类型将继承新方法。一开始使用的就是一个能正常工作的类型。用户的源代码甚至不需要重新编译。
  • 向接口添加一个方法,会强迫接口的继承者更改其源代码并重新编译

5 C#中的接口

下面看几个C#接口的例子及实现。其实单纯的为了应用接口而应用接口是没什么意思的,我的理解,接口一定是跟软件设计相关,它是比面向对象更高一个层次,下面这些例子,第一个例子很常见,我们平常就是这么用的。第二个例子不是特别常见,因为接口的实现类,一般不会允许再可以有派生类,一般来讲,都会是直接实现。第三个例子,只是看看我们接口复杂的用法,相信工作中很少会遇到这样写得。但如果这样写一定有这样写得道理。

5.1 接口隐式方法实现

代码如下:

   /// <summary>
    /// IMessage
    /// </summary>
    interface IMessage
    {
        void ShowMessage();
    }
    /// <summary>
    /// ConsoleMessage
    /// </summary>
    class ConsoleMessage : IMessage
    {
        #region IMessage 成员
        /// <summary>
        /// ShowMessage
        /// </summary>
        public void ShowMessage()
        {
            Console.WriteLine("ConsoleMessage.ShowMessage()");
        }
        #endregion
    }

测试代码如下:

        /// <summary>
        /// Main
        /// </summary>
        /// <param name="args">args</param>
        static void Main(string[] args)
        {
            // 1、不加virtual实现接口
            ConsoleMessage consoleMsg = new ConsoleMessage();
            // 结果:ConsoleMessage.ShowMessage()
            ((IMessage)consoleMsg).ShowMessage();
            // 结果:ConsoleMessage.ShowMessage()
            consoleMsg.ShowMessage();
         }    

这是最常用的情况。一个接口,一个实现类。可以通过接口调用方法, 也可以通过实现类调用方法。

5.2 接口的实现加virtual的情况

代码如下:

    /// <summary>
    /// IMessage
    /// </summary>
    interface IMessage
    {
        void ShowMessage();
    }

    /// <summary>
    /// VirtualMessage
    /// </summary>
    class VirtualMessage : IMessage
    {
        /// <summary>
        /// ShowMessage
        /// </summary>
        public virtual void ShowMessage()
        {
            Console.WriteLine("VirtualMessage.ShowMessage()");
        }
    }

    /// <summary>
    /// ExtendVirtualMessage
    /// </summary>
    class ExtendVirtualMessage : VirtualMessage
    {
        /// <summary>
        /// ShowMessage
        /// </summary>
        public override void ShowMessage()
        {
            Console.WriteLine("ExtendVirtualMessage.ShowMessage()");
        }
    }

测试代码:

     /// <summary>
        /// Main
        /// </summary>
        /// <param name="args">args</param>
        static void Main(string[] args)
        {
            ///3、重写VirtualMessage的ShowMessage接口
            ExtendVirtualMessage extendVirtualMsg = new ExtendVirtualMessage();
            // ExtendVirtualMessage.ShowMessage()
            ((IMessage)extendVirtualMsg).ShowMessage();
            // ExtendVirtualMessage.ShowMessage()
            ((VirtualMessage)extendVirtualMsg).ShowMessage();
            // ExtendVirtualMessage.ShowMessage()
            extendVirtualMsg.ShowMessage();
        }

实现类的派生类重写接口方法,可用接口,实现类,实现类的派生类去调用方法,但结果都是一致的。

5.3 接口的显示方法实现

显示接口方法实现的定义:将定义方法的那个接口的名称作为方法名前缀(例如IDisposable.Dispose),就会创建显式接口方法实现。注意C#不允许在显式接口方法指定可访问性(比如public或者private)。但是编译器生成方法的元数据时,可访问性会自动设为private

代码如下:

    /// <summary>
    /// IMessage
    /// </summary>
    interface IMessage
    {
        void ShowMessage();
    }
    /// <summary>
    /// ConsoleMessage
    /// </summary>
    class ConsoleMessage : IMessage
    {
        #region IMessage 成员

        /// <summary>
        /// ShowMessage
        /// </summary>
        public void ShowMessage()
        {
            Console.WriteLine("ConsoleMessage.ShowMessage()");
        }
        #endregion
    }
    /// <summary>
    /// EIMIMessage
    /// </summary>
    class EIMIMessage : ConsoleMessage, IMessage
    {
        /// <summary>
        /// ShowMessage
        /// </summary>
        public new void ShowMessage()
        {
            Console.WriteLine("EIMIMessage.new ShowMessage()");
        }
        #region IMessage 成员
        /// <summary>
        /// ShowMessage
        /// </summary>
        void IMessage.ShowMessage()
        {
            Console.WriteLine("EIMIMessage.IMessage.ShowMessage()");
        }
        #endregion
    }

测试结果如下:

     /// <summary>
        /// Main
        /// </summary>
        /// <param name="args">args</param>
        static void Main(string[] args)
        {
            // 4、显示实现接口等综合类
            EIMIMessage eimiMsg = new EIMIMessage();
            // EIMIMessage.IMessage.ShowMessage()
            ((IMessage)eimiMsg).ShowMessage();
            // ConsoleMessage.ShowMessage()
            ((ConsoleMessage)eimiMsg).ShowMessage();
            // EIMIMessage.new ShowMessage()
            eimiMsg.ShowMessage();
            Console.Read();
        }

1、EIMIMessage 实现IMessage接口,显示实现接口方法ShowMessage,显示实现的接口方法,只能通过接口去调用。所以结果是:EIMIMessage.IMessage.ShowMessage()
2、EIMIMessage 的基类ConsoleMessage,如果转换成:ConsoleMessage,则调用的就是ConsoleMessage类实现的方法。
3、EIMIMessage 类继承ConsoleMessage,是不能够继承ConsoleMessage.ShowMessage的方法,只能通过new 关键字重新写一个方法。因此用EIMIMessage 的对象去调用,则是重写的这个类。

谨慎使用显示接口方法实现

  • 没有文档解释类型具体是如何实现一个EIMI方法,也没有Microsoft Visual Studio“智能感知”支持
  • 值类型的实例在转换成接口时装箱
  • EIMI不能由派生类型调用

5.4 泛型接口

泛型接口的优点:

  • 泛型接口提供了出色的编译时类型安全性

有的接口比如(非泛型Icomparable接口)定义的方法使用了Object参数或Object返回类型。在代码中调用这些接口方法时,可以传递对任何类型的实例的引用。但这通常不是我们期望的

  • 处理值类型的时候,装箱次数会减少
     static void TestInterface()
        {
            Int32 x = 1;
            Int32 y = 2;

            // x转换为接口类型本身是要装箱的
            IComparable<Int32> c = x;

            // CompareTo方法本来就接受int类型,所以 y不需要装箱
            c.CompareTo(y);

            // 类型安全,编译不通过
            c.CompareTo("2");
        }
  • 类可以实现一个接口若干次

如同时实现Int32的IComparable和string的IComparable

5.5 泛型和接口约束

  • 可以将泛型约束为多个接口
     public static class SomeType
        {
            private static void Test()
            {
                Int32 x = 5;
                Guid g = new Guid();

                // 对M调用能通过编译,因为Int32实现了IComparable和IConvertible
                M(x);

                // 编译时错误,因为Guid只实现了IComparable,没有实现IConvertible
                M(g);
            }

            private static Int32 M<T>(T t) where T : IComparable, IConvertible
            {
                Console.Write(t);
                return 0;
            }
        }
  • 传递值类型减少装箱次数

C#编译器为接口约束生成特殊IL指令,导致直接在值类型上调用接口的方法而不装箱。不用接口约束便其他方法让C#编译器生成这些IL指令。 如果值类型实现了一个接口方法,在值类型的实例上调用这个方法不会造成值类型的实例装箱。

6 参考资料

时间: 2024-10-13 12:06:38

为什么要使用接口?的相关文章

微信公众号可通过现金红包接口发放微信支付现金红包(附开发教程)

农历新年将至,支付宝红包打了一仗,微信在朋友圈屏蔽了它的分享,但单防守还不行,进攻才是最好的防守.昨日,微信支付现金红包接口正式开放,只需开通微信支付,即可接入现金红包.微信公众号也可以发放现金红包了! 通过现金红包接口,公众号开发者可以策划相关运营活动,向用户发放微信支付现金红包,更好的达到品牌推广及回馈用户的效果. 1.商户调用接口时,通过指定发送对象以及发送金额的方式发放红包,这样的方式,允许商户灵活的应用于各种各样丰富的活动场景 2.领取到红包后,用户的资金直接进入微信零钱,避免繁复的领

.NET深入解析LINQ框架(五:IQueryable、IQueryProvider接口详解)

阅读目录: 1.环路执行对象模型.碎片化执行模型(假递归式调用) 2.N层对象执行模型(纵横向对比链式扩展方法) 3.LINQ查询表达式和链式查询方法其实都是空壳子 4.详细的对象结构图(对象的执行原理) 5.IQueryable<T>与IQueryProvider一对一的关系能否改成一对多的关系 6.完整的自定义查询 1]. 环路执行对象模型.碎片化执行模型(假递归式调用) 这个主题扯的可能有点远,但是它关系着整个LINQ框架的设计结构,至少在我还没有搞懂LINQ的本意之前,在我脑海里一直频

.NET深入解析LINQ框架(四:IQueryable、IQueryProvider接口详解)

阅读目录: 1.开篇介绍 2.扩展Linq to Object (应用框架具有查询功能) 2.1.通过添加IEnumerable<T>对象的扩展方法 2.2.通过继承IEnumerable<T>接口 2.3.详细的对象结构图 3.实现IQueryable<T> .IQueryProvider接口 3.1.延迟加载IEnumertor<T>对象(提高系统性能) 3.2.扩展方法的扩展对象之奥秘(this IQueryable<TSource> so

Python:hashlib加密模块,flask模块写登录接口

hashlib模块 主要用于加密相关的操作,(比如说加密字符串)在python3的版本里,代替了md5和sha模块,主要提供 sha1, sha224, sha256, sha384, sha512 ,md5 这些加密方式 import  hashlib m = hashlib.md5()   #用md5加密的方式(md5加密后无法解密),创建一个md5的对象 m.update(b"Hello")  #b代表二进制字节bytes,把字符串hello转成字节,然后加密:用b给一个变量转换

谈谈-Android中的接口回调技术

Android中的接口回调技术有很多应用的场景,最常见的:Activity(人机交互的端口)的UI界面中定义了Button,点击该Button时,执行某个逻辑. 下面参见上述执行的模型,讲述James对Android接口回调技术的理解(结合前人的知识和自己的实践). 使用一个比喻很形象地说明:客户端有个疑问打电话请教服务端,但服务端无法现场给出解答,相互之间约定:服务端一旦有答案,使用电话的方式反馈给客户端. 以上有三个主体:客户端.服务端和接口(方式). 接口回调的原理框图说明: Demo界面

微信jssdk批量添加卡券接口

1)首先是官方接口文档: 1.批量添加卡券接口:https://mp.weixin.qq.com/wiki?action=doc&id=mp1421141115&t=0.08619731531288366&token=&lang=zh_CN#wxkq3 : 2.卡券扩展字段cardExt说明:https://mp.weixin.qq.com/wiki?action=doc&id=mp1421141115&t=0.08619731531288366&t

微信公众号调用接口返回码

返回码 说明 -1 系统繁忙,此时请开发者稍候再试 0 请求成功 40001 获取access_token时AppSecret错误,或者access_token无效.请开发者认真比对AppSecret的正确性,或查看是否正在为恰当的公众号调用接口 40002 不合法的凭证类型 40003 不合法的OpenID,请开发者确认OpenID(该用户)是否已关注公众号,或是否是其他公众号的OpenID 40004 不合法的媒体文件类型 40005 不合法的文件类型 40006 不合法的文件大小 4000

MVC下微信企业号网页应用开发调用JSSDK接口不成功问题

在MVC下进行企业微信里的网页应用开发,前台页面中为了调用图像接口,使用了JSSDK.按照官方文档进行了正确配置. 现象:WEB开发工具调试一切正常,但从手机企业微信应用进入页面后接口调用无效(这个页面是从一级页面链接过来的),开了调试模式后,显示config:ok.说明配置无误.经过反复检查,终于发现问题所在. 原因:在一级页面(http://xx.xxx.xxx/main/index)中的链接是使用htmlhelper来写的,即@Html.ActionLink("测试接口",&qu

关于工作中微信分享接口的bug

调用config 接口1的时候传入参数 debug: true 可以开启debug模式,页面会alert出错误信息.以下为常见错误及解决方法: invalid url domain当前页面所在域名与使用的corpid没有绑定(可在该企业号的应用可信域名中配置域名). invalid signature签名错误.建议按如下顺序检查: 确认签名算法正确,可用 http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 页面工具进行校验. 确认c

微信小程序的Web API接口设计及常见接口实现

微信小程序给我们提供了一个很好的开发平台,可以用于展现各种数据和实现丰富的功能,通过小程序的请求Web API 平台获取JSON数据后,可以在小程序界面上进行数据的动态展示.在数据的关键 一环中,我们设计和编写Web API平台是非常重要的,通过这个我们可以实现数据的集中控制和管理,本篇随笔介绍基于Asp.NET MVC的Web API接口层的设计和常见接口代码的展示,以便展示我们常规Web API接口层的接口代码设计.参数的处理等内容. 1.Web API整体性的架构设计 我们整体性的架构设计