去年,我们分享了《40个良好用户界面Tips》,对设计师来说确实很有帮助,今年,Goodui.org已经更新至71条,这些原则都是由Goodui官方精心整理,认为这些都是非常重要的设计要点,所以对于设计师来说,建议学习一下。
01 尝试使用一列的布局替代多列布局

02 给用户一些小的利益,别看上去那么赤裸裸

03 合并相似的功能

04 尝试展示来自用户的赞扬,而不是自我表扬

05 重复核心行动点

06 统一视觉规范,提升可识别性

07 尝试使用推荐的口吻,而不是让用户感觉面对一台冷冰冰的机器

08 给用户吃「后悔药」的机会

09 告诉用户产品适用的人群,而不是人人都通用

10 将文案写得更加的直接,而不是一堆废话

11 增强主行动点的视觉冲击力,提升它在页面中的可对比性

12 让用户知道你从哪儿来更易于拉近与用户的关系

13 将表单做的简单点,确保用户在抓狂之前能进入下一步

14 尽量将用户需要选择的信息展示出来而不是藏起来

15 页面的排版需要考虑用户是否会漏掉底部信息

16 如果页面的底部有需要关注的行动点,别让文中过多的外链带走了用户

17 确保用户知道自己目前的状态

18 将利益点融合在行动点中,增强用户的点击欲望

19 将行动点与当前信息结合起来

20 将简要的表单合并到页面中,减少调整页面带来的用户流失

21 适当的增加延迟动效,让用户感知到页面的变化

22 让新用户从尝试产品入手,而不是一来就面对冷冰冰的注册表单

23 减少使用线框,这会过多的吸引用户注意力,而且会让页面看上去透不过气

24 给用户推销你能给他带来的利益,而不是功能

25 一定要注意0结果页面的设计,这也是引导用户的好地方

26 给用户选择退出的权利,特别是邮件订阅

27 注意界面元素的一致性,降低用户学习成本

28 给下拉框增加一些预设值,降低用户填写成本

29 延续用户日常的使用习惯,而不是重新创造

30 尝试告诉用做些事情降低自己的损失,而不是提升收益

31 提升页面的视觉层次,增强可阅读性

32 将同类的操作合并在一起,降低用户的认知成本

33 表单及时校验,而不是统一提交后在告诉用户填错了

34 尝试将表单输入变得更加宽容,让用户的填写更加简单

35 通过时间增强紧迫感

36 提供用户可预见性的操作,降低用户的心理成本

37 尽可能的帮助用户选择,而不是让用户想破脑袋

38 尽可能将操作区域放大,降低用户操作成本

39 页面加载速度很重要,尽可能让用户感受到你的网站速度很快

40 如果可以,增加键盘快捷键,提升操作效率

41 尝试通过对比来让用户感知到性价比

42 尝试对进度条进行「设计」来降低用户等待的焦虑

43 根据用户选择逐步展示信息,降低无效信息对用户的干扰

44 有时候较小的承诺比「夸海口」会更容易让用户信服

45 尝试将提示信息弱化,减少对用户操作的干扰

46 尽量通过系统的功能来简化用户的操作

47 用文本配合图标来降低用户的认知成本

48 用更自然的语言代替冷冰冰的机器

49 放出一些摘要信息来帮助用户识别是否需要进一步了解

50 在关键的页面增加用户权益信息,增强用户进一步操作的信心

51 将价格进行换算,让用户感觉这很便宜

52 记得在成功页面感谢用户

53 将数字转化成易于用户阅读的形式,而不是冷冰冰的机器语言

54 告诉用户选择的权利和自由「诱惑力」

55 尝试让语言更具「诱惑力」

56 通过设计引导用户的注意力

57 通过友好的对比来展示产品,为用户做决定提供帮助

58 通过任务机制来提升用户的满足感

59 让用户了解接下来将要发生什么事情

60 尝试用更幽默一些的语言文案

61 任何操作之后都要给出反馈,让用户知道操作已经生效

62 注意动效的真实使用情况(Amazon 的类目菜单就是一个很好的例子)

63 注意排版的,不要让信息过于拥挤

64 尝试用讲故事的方式来传递信息,增强用户的代入感

65 尽量给用户展示真实的信息,不要欺骗

66 随着用户的不断熟悉简化界面

67 试着用用户的口吻展示信息

68 在表单中增加一些提示信息,减少错误的几率

69 用简单的文案传递核心关注的信息,少一些废话

70 尝试使用响应式布局

71 视觉表达要清晰,而不是模棱两可

这71条设计原则虽然针对 Web 设计,但有些部分在移动产品设计中同样有效。翻译过程只保留了图片和标题,更多详细内容可以访问 GoodUI 官网:
http://goodui.org/
原文:http://mathewsanders.com/designing-adaptive-layouts-for-iphone-6-plus/
翻译:叮当当咚当当小胖妞呀
从IOS6开始,苹果公司就一直建议我们使用自适应布局,但是迄今为止,我发现大家都在回避这个问题,考虑的最多的仍然是固定布局。
iPhone 6的上市让人们很难再去逃避自适应布局这个问题,四种屏幕尺寸(如果要支持iPad就要上升到5种)、三种分辨率和转向似乎让着手于自适应布局变得更加简单。

在文章的最后,你应该能流畅使用 storyboards、 约束(constraints)和 size class特性,这三个是Apple为开发和制作自适应布局提供的Xcode工具。
所以下载Xcode6,给自己来杯饮料,留上一个小时的时间,让我们开始吧!
- Storyboards
- 模拟尺寸
- 约束
- 头部和尾部空间
- 横向空间约束
- 同等宽度约束
- 纵横比约束
- 约束管理
- 添加约束
- 检查和编辑现有约束
- 删除约束
- 布局问题和冲突
- 错位视图警告
- 约束缺失错误
- Size Classes
- 宽度和高度特性
- 我们的目标…
- 为通用的size class添加约束
- 为iPhone纵向布局添加约束
- 为iPhone横向布局添加约束
- 编辑助手:设备预览
- 为iPad布局添加约束
- 使用布局和间隔视图
- 布局视图样例
- 间隔视图样例
- 下一步
Storyboards
Xcode中,storyboards可以让你在屏幕上拖动和放置原生对象(例如按钮、图片、文本框和标签)并且定义每个屏幕之间如何连接。
在Xcode专业术语中,可以看到、摸到、互动的用户界面元素,我们称之为 视图(按钮、图片、文本框、标签等等)。
包含并管理所有那些视图的屏幕被称为 视图控制器,我倾向于交替使用这些术语。
当我们在一个storyboard上添加视图控制器的时候,它的纵横比其实跟任何设备都不匹配,事实上,它是一个完美的600pt*600pt的正方形:

这提醒了我们,storyboard屏幕并不代表特定硬件上的屏幕,而是 任何IOS设备的抽象表现。
模拟尺寸
也许你不介意在600pt*600pt的画布上操作,但是在实际大小上操作可能会更有帮助。
我们可以非常方便的在Xcode里改变视图控制器模拟的尺寸和转向:

约束
向你们展示约束的最好方法是实例。
我们先创建一个简单的包含一个屏幕的storyboard(模拟4英寸iPhone的尺寸),再添加两个相邻的正方形。

当我们在竖屏中运行app的时候,这两个正方形完全按照我们的布局排列,当我们变成横屏时,它们仍然忠于自己的坐标:

当我们使用iPhone 6模拟器运行项目的时候,我们可以再一次看到,我们的布局并没有自适应不同的屏幕尺寸,屏幕右边多出了可见的空白区域。

这是由于没有约束,这些对象仍然会按照我们在storyboard上创建的x,y坐标和面积来定位。
所以让我们开始添加约束,看看会对它们有些什么影响。
头部和尾部空间
我们在蓝色方块前添加10pt的头部空间约束,在红色方块后添加10pt的尾部空间约束。

当我们运行项目的时候,约束把蓝色方块固定在屏幕左侧,把红色方块固定在右侧。

横向空间约束
我们在两个方块之间再添加一个10pt的横向空间约束,就像上一个约束一样,这样会让两个方块之间有一个固定的空间。

当我们运行项目的时候,会发现一个意料之外的结果:我们所有的约束都满足了,但是为了满足所有约束,其中一个方块被拉伸了。
这似乎告诉我们这样一件事:除非被告知,否则IOS会尽量让大多数对象都保持“自然”大小。

同等宽度约束
我们添加一个同等宽度约束。

当运行项目的时候,我们可以看到两个方块宽度的增量相同。

纵横比约束
最后,对两个方块添加纵横比约束。

这个约束保证了宽度和高度的比永远是相同的。
当我们运行app的时候,我们可以看到每个方块的宽度在增加,高度也同时在增加。

用iPhone 6模拟器运行项目,覆盖我们之前添加过的约束,你可以看到这两个正方形是如何利用可用空间来拉伸的。

约束管理
现在你已经看到了我们是如何使用约束的,下面我们来介绍一下具体操作。
提示:尽量少使用约束
添加约束的一个要点是试着挑战自己,越少使用约束越好。
虽然我并不认为添加的约束数量能够很大程度上影响IOS的性能,但是越少的使用约束,你的布局就会越好维护。
添加约束
在storyboard中添加约束有三个方法:
- 约束弹窗也许最好的方法就是选择一个或多个对象,从其中一个弹窗中添加约束。我认为这是个很好的方法,因为可以看到现有约束的范围。如果有一条约束不可用,可能就意味着你需要两个或更多对象来实施这条约束。

- ctrl + 拖动你可以按住ctrl键,同时拖动到一个对象上(可以是相邻对象、父级对象或者是自身),会出现一个浮层告诉你可以被添加的约束有哪些。这是我最喜欢的添加约束的方法,因为你不需要把你的鼠标移动到大老远的底部再回到对象。

- 菜单/绑定你也可以选择一个或多个对象,在菜单中点击 editor -> pin来选择约束,这其实是最没有效率的方法,但是如果你发现自己不停的重复添加一种约束,也许为一个或多个选项添加绑定更合理一点。
检查和编辑现有约束
检查视图中应用的约束最简单的办法就是选择视图,切换到Size检查面板。
或者在文档大纲层次面板中切换constant数值。
无论是哪种方法,选择约束可以让你直接更新它。

删除约束
同样的,约束也可以通过高亮+点击删除按钮来删除。
要删除一个视图的所有约束,或者屏幕中的所有约束,在布局问题弹窗中有一条捷径:

布局问题和冲突
当我们在storyboard中添加约束的时候,Xcode总会给出一些关于这些约束的警告或者错误。
有时候这些问题可以忽略不计,但是更多的时候,它们必须被解决。
查看约束警告和错误最好在文档大纲面板中,每个视图控制器会有一个红色或者黄色的icon来表示是不是有布局问题:

错位视图警告
一个比较常见的警告是错位视图警告,如果约束规定这个视图应该在的地方,和这个视图实际在的地方不匹配,那么这种警告随时会出现。
当你转换模拟尺寸或者不小心用鼠标移动了一个视图,这些警告也会出现。
点击一个错位的视图,屏幕上会出现一个虚线框,告诉你约束规定了这个视图应该在的位置。

如果点击警告,会出现一个带有几个选项的浮层,你可以选择让Xcode更新约束来匹配storyboard上的位置,也可以让Xcode更新框架来移动或者拉伸视图,使它们回到约束规定的位置。
缺失约束错误
让我们回到一开始蓝方块和红方块的例子,我们没有添加过一个关于纵向位置的约束,但当我们运行app的时候看起来完全没问题,因为IOS会认为纵向位置就是我们在storyboard上放置的位置,不过为了避免一些意料之外的行为,我们最好还是规定一下。
在 顶部布局向导添加顶部空间约束可以消除一些说不定道不明的约束和错误。

Size Classes
为了在大多数基础布局或者更高级的布局上使用约束,你需要同时使用size classes。
Size classes是一种能够告诉你物理设备宽度和高度的特性。
当我们在storyboard的屏幕上添加对象或者约束时,只有设备符合当前的宽高特性,对象才会显现,约束才会被应用。
这是一个非常有用的方法,它让我们确定了不同设备和转向下布局的变化。
高度和宽度特性
使用 紧凑(compact)、 任意(any)和 正常(regular)这三种的组合,可以让我们确定一些范围内的设备布局。
虽然不能涉及每一个变化(比如不能确定iPhone 6 Plus的竖向模式,也不能让iPad的转向消失),但是大多数的变化都可以确定。

我们说过,介绍size classes最简单的方法是实例,所以让我们看一个例子。
我们的目标…
作为例子,我们做一个Instagram详情页的简单版本,可以适应大屏和转向。
我们的目标是创建一个布局,它可以机智的适应更大的iPhone 6设备(我说的机智,是指只有照片会放大,其他的元素如头像照片仍然不变),并且当设备横屏的时候,图片和元数据会并肩排列,而不是像竖屏时的上下排列。

为通用的size class添加约束
跟之前的例子不同,这次我们不使用模拟尺寸度量,我们使用通用size class的抽象方形布局,这样会使我们记住,为这个size class添加的任何视图和约束,只能是那些添加在任意屏幕尺寸和转向上的视图和约束。
我们需要用到这些约束:

除了必要的空间、间隙和纵横比约束,我们还需要让某些对象排列在顶部或者底部。
现在,在你的storyboard上添加视图和约束吧。做这步的时候,我的storyboard长这样:

注意,现在我们有了所有转向上所需要的元素,但是我没有费心完成每个转向上的布局,下一步我们才会做!
为iPhone纵向布局添加约束
现在,我们把size class切换到 紧凑宽度和 正常高度,这个尺寸特性的组合适用于任何竖屏下的iPhone设备。
如果要切换size classes,点击storyboard中下方的size class标签,选择你想要看到的宽高组合。

注意,当你切换size class时,视图控制器的尺寸会更新来显示新的抽象布局。
最后,你可以重新定位、拉伸视图和添加竖屏上的约束了。这里有一些我添加到竖向布局上的约束:

这是我做到这步时,我的storyboard的样子:

在这个阶段,你可以用任何的iPhone模拟器(3.5、4、4.7或者5.5英寸屏幕)来运行你的项目,看看竖屏情况下的布局是否合理,虽然如果转向成横屏时,布局看上去会一团糟。
注意,我们没有固定图片的宽度,我们只是简单地把图片的左右边缘固定在屏幕两侧。当变为更大的iPhone 6屏幕尺寸时,图片会被拉伸,又因为我们添加了一个固定图片纵横比的约束,所以高度也会同时增加。

为iPhone横向布局添加约束
现在切换size class到 任意宽度和 紧凑高度,这种尺寸特性的组合适用于任何横屏下的iPhone设备,并且会为了满足横屏视图下的目标更新布局。
这次,图片的顶部、左边和底部边缘都被固定在父级视图的边缘。
这个局部另一个有意思的地方是,在评论标签上添加的尾部空间约束。
当图片的约束使得图片变大的时候,这个标签上的约束会使得自身变窄。为了适应这种视图下的文本,文本高度需要增加到两行——的确如此!

下图是我做到这步时storyboard的样子。注意,在文档大纲中,一些约束会稍稍渐隐,这些约束是在竖向视图中我们添加的,它们仍然存在,但是当我们选中当前的宽高特性时,它们不会被应用。

也要注意,当你转换宽高特性时,storyboard会更新以便显示你为那些特性增加的约束。太棒了!

现在运行项目,我们会发现当转向改变时,我们有了一个既适用于横屏又适用于竖屏的布局,更棒的是在转向时,会有一个完美的过渡动画。

我把整个过渡动画放慢,这样你们能看的更加清楚。注意动画中也有层级关系,正由于此,即使在正常布局下视图并没有重叠,我们也需要考虑如何安排视图的层级关系……
编辑助手:设备预览
Xcode另外一个很有用的东西:设备预览助手。你不再需要无数次运行项目来检查你的布局是否正确,你只需要使用编辑助手storyboard预览,选择你想要的所有设备和转向就可以了。
这并不是完美的(比如导航条的颜色在这个例子中缺失了),但是它却是一个很好地选择,它可以让你把你自己的语言切换到双倍长度伪语言,可以在你的storyboard中重复任何文本。

这是我storyboard上的预览助手,它展示了一个3.5英寸横屏和4英寸竖屏的iPhone,你可以看到我还需要再加工加工来适应更长的标签……-_-
为iPad布局添加约束
现在,切换size classes到 正常宽度和 正常高度,这是iPad横屏和竖屏的特性。
就像之前一样,我们重新定位、拉伸我们的视图。对于iPad布局,我决定使用固定尺寸的图片(所以它不会像在iPhone上那样切换横竖屏时会改变大小),元数据都显示在图片底部。
下图是我在重新排列视图并添加了约束之后的storyboard:

到现在为止,我们为某些特别的size class特性添加了约束,但是现在我们要尝试些不同的东西。
由于iPad上会有多余的空间,我们不要仅仅只是重排视图,让我们来加一点额外的内容。对于这个例子来说,我们再加两张图片(也许是在这张主照片之前和之后拍摄的照片)。
这是我的storyboard更新之后的样子:

我原本可以手动输入这些次级图片的宽高,但我没有,取而代之的是我让它们的尺寸变成主图片的某个比例。
这样做的好处是如果我们决定改变主图片的尺寸,布局的其他部分会自动的计算并且更新次级图片的宽高,而不用我们手动输入。

这是一张我截的图,我改变了主图片的宽度约束,可以看到其他的部分也随之更新了。
我没有在iPad模拟器上运行项目并截屏,不过这里有一些横屏和竖屏的效果图:

使用布局和间隔视图
Xcode中有些约束我们可以随时运用,但是对于一些些常见的布局,我们需要一点帮助。
布局视图样例
要把一个视图的边缘固定在父级视图的边缘,或者把它固定在父级视图的正中心是件很简单的事情,~~但是我没有发现简便的方法,让视图固定在离正中心有一段固定距离的地方。~~感谢Jeff Nouwen指出,在把视图固定在中间后,你可以改变constant值来达到你的期望。
理论上来说,我们需要的是一个‘ 中心排列导向’,即任何视图都能水平和垂直居中与父级视图中:

为了实现这个目标,通过现在我们可以使用的约束,我们把我们的视图嵌入一个外层视图(这个外层视图没有背景色,只是为了帮助我们布局而存在),可以把它定位在父级视图的中间。
通过这个方法,你的约束看起来可能像这样:

现在我比较喜欢让我的布局层级尽量平。另外一个不使用外层视图的方法,我叫它 布局视图。
使用这种方法,我倾向于在storyboard中添加一个颜色明亮的视图,然后把它的hidden属性设置为true,你仍然可以在storyboard布局中看到它(虽然稍稍渐隐),但是运行模拟器的时候它不会出现。
现在你在你的视图和布局视图中可以添加 居中排列(align center to center)。

间隔视图样例
之前我们看到了我们是如何固定视图边缘到父级视图边缘的间隙,使得当父级视图变大时,间隙约束也会让视图变大。
但是如果我们想要视图仍然保持原来的大小,在父级视图变大时,视图之间的间隙也变大呢?

理论上来说,我们想要某种类似 同等宽度约束的约束,只不过同等宽度约束是作用在视图上,我们想让它作用在约束上。
此时我们需要添加 间隔视图来帮助我们布局,但由于我们不想在运行app时看到它们,我们会把它们的hidden属性设置为true。
使用这项技术的方法,是为每一个你想要等比增长的间隙添加一个间隔视图,把其他视图的边缘固定在间隔视图的边缘上,然后为所有的间隔视图添加 同等宽度约束。

下一步
现在希望你们已经完全有信心开始探索应用约束的布局了。
不要指望能即刻成功,Xcode是一个非常复杂的工具,除了storyboard和约束之外它还有很多其他功能,有些功能刚开始使用会觉得很神秘和困惑。就像其他复杂的工具一样,在你熟悉它的怪癖之前你还需要一段适应时间,但是我建议你尽早的去熟悉它,因为我预计(至少我希望)下一代设计师会更多地使用Xcode这样的工具而非Photoshop。
如果你是一位创建设计规范的设计师,并想让IOS开发者遵循你的规范,你应该开始考虑和你的设计团队沟通的最好方法。也许你会创建一个视觉语言来描述你想要应用的约束。
我个人认为,设计师应该更多地承担一些他们创建工作上的责任,而不是让一个前端开发人员重新创建设计意图,而设计师只是管理storyboard文件。
如果你发现这个教程上有任何难以理解的地方,或者有错误的敌方,请让我知道,我会尽快更新这篇文章。
PHP如何获取表单的POST数据呢?本文介绍3种获取POST数据的方法,并将代码附上,希望可以帮助到你。
一、PHP获取POST数据的几种方法
方法1、最常见的方法是:$_POST['fieldname'];
说明:只能接收Content-Type: application/x-www-form-urlencoded提交的数据
解释:也就是表单POST过来的数据
方法2、file_get_contents(“php://input”);
说明:
允许读取 POST 的原始数据。
和 $HTTP_RAW_POST_DATA 比起来,它给内存带来的压力较小,并且不需要任何特殊的 php.ini 设置。
php://input 不能用于 enctype=”multipart/form-data”。
解释:
对于未指定 Content-Type 的POST数据,则可以使用file_get_contents(“php://input”);来获取原始数据。
事实上,用PHP接收POST的任何数据都可以使用本方法。而不用考虑Content-Type,包括二进制文件流也可以。
所以用方法二是最保险的方法。
方法3、$GLOBALS['HTTP_RAW_POST_DATA'];
说明:
总是产生 $HTTP_RAW_POST_DATA 变量包含有原始的 POST 数据。
此变量仅在碰到未识别 MIME 类型的数据时产生。
$HTTP_RAW_POST_DATA 对于 enctype=”multipart/form-data” 表单数据不可用
如果post过来的数据不是PHP能够识别的,可以用 $GLOBALS['HTTP_RAW_POST_DATA']来接收,
比如 text/xml 或者 soap 等等
解释:
$GLOBALS['HTTP_RAW_POST_DATA']存放的是POST过来的原始数据。
$_POST或$_REQUEST存放的是 PHP以key=>value的形式格式化以后的数据。
但$GLOBALS['HTTP_RAW_POST_DATA']中是否保存POST过来的数据取决于centent-Type的设置,即POST数据时 必须显式示指明Content-Type: application/x-www-form-urlencoded,POST的数据才会存放到 $GLOBALS['HTTP_RAW_POST_DATA']中。
二、演示
1、PHP 如何获取POST过来的XML数据和解析XML数据
比如我们在开发微信企业号时,如何处理用户回复过来的数据呢?
文档:http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF
首先查阅文档,可知道:启用开发模式后,当用户给应用回复信息时,微信服务端会POST一串XML数据到已验证的回调URL
假设该URL为 http://www.xxx.com
Http请求方式: POST
http://www.xxx.com/?msg_signature=ASDFQWEXZCVAQFASDFASDFSS×tamp=13500001234&nonce=123412323
POST的XML内容为:
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[this is a test]]></Content> <MsgId>1234567890123456</MsgId> <AgentID>1</AgentID> </xml>
那么怎么接收这段内容呃?
这时就可以用到:方法2(file_get_contents(“php://input”))、方法3($GLOBALS['HTTP_RAW_POST_DATA'])
方法2(file_get_contents(“php://input”)):
$input = file_get_contents("php://input"); //接收POST数据
$xml = simplexml_load_string($input); //提取POST数据为simplexml对象
var_dump($xml);
方法3($GLOBALS['HTTP_RAW_POST_DATA'])
$input = $GLOBALS['HTTP_RAW_POST_DATA']; libxml_disable_entity_loader(true); $xml = simplexml_load_string($input, 'SimpleXMLElement', LIBXML_NOCDATA); var_dump($xml);
PHP获取POST数据的3种方法及其代码分析,希望可以帮到你。
今天算是长见识了,项目发布到服务器上面了,但是客户在使用的时候发现,只要进入新增页面和修改页面。再进行操作就会自动跳转到登陆页面(我设置了session保存用户登陆信息),而别的页面就不会出现这个问题。从下午开始找个问题,开始以为不知道只有这两个页面有问题,以为全部都是这样的问题,是IIS的设置问题。我将session的超时时间设置了3个小时,发现还是会跳转到登陆页面。也在web.config文件里面设置了超时时间。但是效果还是一样的。自己测试了一下午,发现只有新增页面和修改页面会出现这样的问题(本机测试没问题/测试服务器上测试也没问题)。经过几次实验,发现确实只有这两个页面会有问题,那就可以断定:不是IIS设置问题,也不是web.config的问题。本地调试也不出现这样的情况,没办法,只能等客户下班之后,没人用了才到正式服务器上去慢慢的调试,最后想个笨办法,将其中一个页面的.cs文件里面的代码一句一句的删掉,可没想到我都将cs文件里面的代码全部删除了,还是会出现这样的情况,我当时就纳闷了。不是事件的问题,难道是HTML页面出了问题???
既然耐着性子删了cs文件的代码。我就继续删!将aspx页面里面的HTML代码和JS代码也一个一个的删掉,一个一个控件删掉测试,从下午上班一直测试到晚上11点,眼睛都看花了,终于,在我将aspx页面的其中几个控件删除之后发现问题了!页面不跳转了!这下来劲了,肯定是这几个控件的原因,于是乎,我就一个一个控件还原回去,不跳转!继续还原!!当我还原到<img src="" >这个控件的时候测试,发现问题了!只要我一加上<img src="">这个标签!页面就跳转到登陆页面了。问题肯定出在这了!但是我又想不通了,为什么就这个HTML标签一加上就会出问题,这应该不关session什么事啊,怎么会加上这个标签页面就直接跳转了呢?
在网上找了下资料,没找到相关的资料,后来试着将img 标签的src=""加上图片,src="imges/001.jpg" 再测试,发现页面不跳转了!!原来问题出现在这里!
src=""为空的情况下,可能导致session丢失!跟经理说了下这个情况,他也很惊奇还没见过一个HTML标签会导致session丢失的情况,因为在本地和测试服务器上测试的时候都没这样的情况,后来猜测了下,可能是IIS的问题,可能是IIS解析的时候解析到src=""这个地方解析不了,导致程序出问题。但这只是个人猜测,正式服务器上我也没权力当时去打补丁,一个大公司的正式服务器,我要打补丁去了,那他们别的网站和系统不全当机了?所以就只要想了个办法,将src=""里面加上图片,幸好这个img标签是隐藏起来的,加了也不影响界面。呵呵。。。
最让人郁闷的是我测试的时候是用Symantec pcAnywhere这个软件远程连接到的正式服务器上。反应慢得可以,简直比电脑没装显卡驱动还慢...唉,不过累也累了,以后碰到这样的情况就有经验了。
我不知道网上有没有人碰到过跟我一样的情况;如果碰到了,希望能给你带来点灵感。哇哈哈。。。
可以创建实现模板的用户控件,这是 ASP.NET 的一项功能,它允许将控件数据与其表示形式相分离。模板化控件不提供用户界面。编写它则是为了实现一个命名容器以及包含属性和方法可由宿主页访问的类。
用户控件的用户界面由页面开发人员在设计时提供。开发人员创建由用户控件定义的类型模板,然后可以向模板添加控件和标记。
创建模板用户控件
-
在 .ascx 文件中,添加要在其中显示模板的 ASP.NET PlaceHolder 控件。
-
在用户控件的代码中,实现 ITemplate 类型的属性。
-
将实现 INamingContainer 接口的服务器控件类定义为要在其中创建模板实例的容器。此容器叫做模板的命名容器。
说明:此控件实质上成了用户控件的嵌套类,但这不是必需的。
-
将 TemplateContainerAttribute 应用于实现 ITemplate 的属性 (property),并将模板命名容器的类型作为参数传递给属性 (attribute) 的构造函数。
-
在控件的 Init 方法中,将以下步骤重复一次或多次:
-
创建命名容器类的一个实例。
-
在命名容器中创建该模板的一个实例。
-
将命名容器实例添加到 PlaceHolder 服务器控件的 Controls 属性。
说明:从使用用户控件的页面的角度来看,模板化用户控件的语法与自定义模板化控件的语法相同。
-
示例 下面的示例演示一个模板化用户控件和一个包含该控件的页面。该用户控件创建一个可在宿主页上声明为 <MessageTemplate> 的模板。该模板控件还公开两个可由宿主页在模板内访问的属性:Index 和 Message。
第一个示例显示模板化用户控件。第二个示例显示包含该用户控件的页面。
<%@ Control language="VB" ClassName="TemplatedUC" %> <%@ Import Namespace="System.ComponentModel" %> <script runat="server" > Private m_messageTemplate As ITemplate = Nothing <TemplateContainer(GetType(MessageContainer))> _ <PersistenceMode(PersistenceMode.InnerProperty)> Public Property _ MessageTemplate() As ITemplate Get Return m_messageTemplate End Get Set(ByVal value As ITemplate) m_messageTemplate = Value End Set End Property Sub Page_Init() If Not (MessageTemplate Is Nothing) Then Dim i As Integer Dim fruits() As String = _ {"apple", "orange", "banana", "pineapple"} For i = 0 To 3 Dim container As New MessageContainer(i, fruits(i)) MessageTemplate.InstantiateIn(container) PlaceHolder1.Controls.Add(container) Next i End If End Sub Public Class MessageContainer Inherits Control Implements INamingContainer Private m_index As Integer Private m_message As String Friend Sub New(ByVal i As Integer, ByVal msg As String) Me.Index = i Me.Message = msg End Sub Public Property Index() As Integer Get Return m_index End Get Set(ByVal value As Integer) m_index = value End Set End Property Public Property Message() As String Get Return m_message End Get Set(ByVal value As String) m_message = value End Set End Property End Class </script> <asp:Placeholder runat="server" ID="PlaceHolder1" />
<%@ Control language="C#" ClassName="TemplatedUC" %> <%@ Import Namespace="System.ComponentModel" %> <script runat="server"> private ITemplate messageTemplate = null; [ TemplateContainer(typeof(MessageContainer)) ] [ PersistenceMode(PersistenceMode.InnerProperty) ] public ITemplate MessageTemplate { get { return messageTemplate; } set { messageTemplate = value; } } void Page_Init() { if (messageTemplate != null) { String[] fruits = {"apple", "orange", "banana", "pineapple" }; for (int i=0; i<4; i++) { MessageContainer container = new MessageContainer(i, fruits[i]); messageTemplate.InstantiateIn(container); PlaceHolder1.Controls.Add(container); } } } public class MessageContainer: Control, INamingContainer { private int m_index; private String m_message; internal MessageContainer(int index, String message) { m_index = index; m_message = message; } public int Index { get { return m_index; } } public String Message { get { return m_message; } } } </script> <asp:Placeholder runat="server" ID="PlaceHolder1" />
<%@ Page Language="VB" %> <%@ Register TagPrefix="uc" tagname="TemplateTest" Src="TemplatedUC.ascx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html > <script runat="server"> Sub Page_Load() DataBind() End Sub </script> <head> <title>Templated User Control Test</title> </head> <body> <h1>Testing Templated User Control</h1> <form id="Form1" runat="server"> <uc:TemplateTest runat="server"> <MessageTemplate> Index: <asp:Label runat="server" ID="Label1" Text='<%# Container.Index %>' /> <br /> Message: <asp:Label runat="server" ID="Label2" Text='<%# Container.Message %>' /> <hr /> </MessageTemplate> </uc:TemplateTest> </form> </body> </html>
<%@ Page Language="C#" %> <%@ Register TagPrefix="uc" tagname="TemplateTest" Src="TemplatedUC.ascx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html > <script runat="server"> protected void Page_Load() { DataBind(); } </script> <head> <title>Templated User Control Test</title> </head> <body> <h1>Testing Templated User Control</h1> <form id="Form1" runat="server"> <uc:TemplateTest runat="server"> <MessageTemplate> Index: <asp:Label runat="server" ID="Label1" Text='<%# Container.Index %>' /> <br /> Message: <asp:Label runat="server" ID="Label2" Text='<%# Container.Message %>' /> <hr /> </MessageTemplate> </uc:TemplateTest> </form> </body> </html>
微软已经开始正式对系统更新的使用者强制检查其所使用的 XP系统是否为盗版的检查,若发现盗版,系统自动更新后,每次启动都提示"您可能是软件盗版的受害者",进入桌面后右下角启动栏里有一个五角星的图案.
相关报道:
即日起微软将启动「正版Windows客户权益独享计划1.0 」 (Windows Genuine Advantage 1.0 , WGA 1.0),用户进入下载中心必须验证是否正版软件,若为盗版软件则不能下载,但是自动更新(Automatic updates)不在此限,所有的用户都可以自动更新修补漏洞。用户在第一次进入Windows update、Microsoft update及Download Center网站进行下载时,将被要求参与WGA验证程序。客户须要下载一个ActiveX控制程序,此程序将自动验证用户计算机所使用的是否为正版 Windows软件。若通过验证,将会有一组Download Key储存在客户计算机中,作为将来进入微软网站进行下载动作时计算机自动辨识之用,微软表示,此验证流程不搜集任何可用来辨认或联络使用者的信息。验证流程已经改善并简化。验证程序将自动验证用户计算机所使用的是否为正版Windows软件,用户不再需键入25码的产品序号,就可以轻松的完成验证过程,大幅降低客户进行验证时的负担。换句话说使用盗版Windows操作系统的用户,将不能直接从下载中心下载Windows Media Player、Antispy等软件,但是依然可以透过自动更新来修补漏洞。
手工解决方法:
方法一:
1.IE => 工具=>Internet 选项 => 程序=> 管理加载项=>IE已经使用的加载项=>Windows Genuine Advantage Validation Tool=>禁用=>然后再上线更新,这样就不会验证了。此WGA(Windows Genuine Advantage Notifications)组件对应文件:legitchechcontrol.dll。WGA是反盗版自动更新验证ActiveX组件,这个正版检验程序植入系统后,会在每次系统启动时,透过网络回报讯息给微软的网站。没更新过的计算机里没有此组件,So..先去update下载此组件后再用此方法去停用此组件,以后即可自动更新了。
2、移除验证码:
计算机=>控制面板=>添加或删除程序=>Windows Installer 3.1(KB893803)=>删除=>重新下载更新档=>windows genuine advantage 不要勾选=>完成。保证不会再出现了(Windows Installer 3.1是修复windows installer安装错误或者提示无法修复MSI出错的微软官方补丁)
3.重启你的计算机,进入安全模式,登陆管理员帐号--保证你拥有进入Windows\system32以及Windows\system32\dllcache路径的权限。在这两个路径下均有一个名为WGATray.EXE的文件。你必须将两个路径下的WGATray.EXE均删除--这将阻止Windows在启动时弹出“盗版XP”气球。
在删除Windows\system32下的WGATray.EXE可能需要一点技巧:
步奏一:WGATray.EXE图标-->右键-->删除-->出现删除确认框后先不要按‘确定’按钮
步奏二:Ctrl+Alt+Del-->打开进程管理器-->找到WGATray.EXE-->删除-->出现删除确认框后先不要按‘确定’按钮
步奏三:先按打开进程管理器的删除确认键,然后用最快速度按步奏一的删除确认键。
步奏四:如果Windows\system32下的WGATray.EXE不会出现,代表操作成功。继续删除Windows\system32\dllcache下的WGATray.EXE。
4.进入注册表,进入
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ Windows NT\CurrentVersion\Winlogon\Notify
删除其中的“WGALOGON”文件夹--这将Windows将无法加载任何有关WGA的DLL文件。
重启计算机,你将暂时告别微软正版增值计划的“骚扰”。
方法二:
在进入Window update 网页后选择「Express(快速)」或「Custom(自订)」按钮前,在 IE 地址栏输入:
void(window.g_sDisableWGACheck='all')
再按下ENTER后,再选取你要更新的方法"快速","自订"即可
此法可以用来破解微软反盗版的检查。系统就不会查你是用什么版本的WIN了
能保证系统更新还是很有必要的。系统更新的目的多数就是防止电脑病毒的需要。
对于使用VOL免激活版(上海政府、xx银行等)的用户,可以使用替换序列号的简单办法。因为目前尚有部分VOL序列号未被封,并且可以通过正版验证。
HCQ9D-TVCWX-X9QRG-J4B2Y-GR2TT (番茄花园版就是使用的这个序列号)
MRX3F-47B9T-2487J-KWKMF-RPWBY(工行版)
QC986-27D34-6M3TY-JJXP9-TBGMD(台湾交大学生版)
点击下载此文件
替换后请到C:\Documents and Settings\All Users\Application Data下删除Windows Genuine Advantage文件夹。以后即可通过正版验证。
如果XP是很老的破解版本(比如零售版的破解版本)用户,无法使用上述序列号,请下载RemoveWGA工具。RemoveWGA 是一个专门用来清除 WGA 的小程序,使用者只要通过它,就可以阻止微软的 WGA 在系统每次启动时企图连回微软网站的动作,且使用它并不需要担心微软的正版验证机制,你还是一样能够正常的使用 Windows update 的功能,两者之间并没有任何冲突。虽然系统仍是破解的,但将不会再有任何提示,和以前没有变化。注:该工具会被部分杀毒软件识别为病毒。如须使用,下载前可能需要暂时禁用或者关闭一下病毒防火墙。使用过后再恢复。
华军下载地址:http://www.onlinedown.net/soft/6914.htm
2000/XP/2003 下 IIS+PHP+MySQL+Zend Optimizer+GD库+phpMyAdmin安装配置
(假设 C:\ 为你现在所使用操作系统的系统盘,如果你目前操作系统不是安装在 C:\ ,请自行修改。)
一、安装 IIS(Windows2003只要安装“应用程序服务器(IIS,ASP.NET)”即可跳过此步):
(1)插入系统盘;
(2)进入控制面板-》添加或删除程序-》添加/删除Windows组件-》在“Internet信息服务(IIS)打勾-》下一步安装。
(3)安装完成后在浏览器地址栏输入 htt://127.0.0.1 检查是否安装正常。
如果没有系统盘,那么下载 IIS 5.1 的安装包(for XP),重复上述步骤,安装时指定路径即可。
IIS下载地址:http://soft.mumayi.net/downinfo/2597.html
二、安装 PHP:
(1)官方下载:http://www.php.net/downloads.php。
(2)下载后得到 php 的 zip 压缩包,解压至 C:\php(这个路径可以随意,下面要是用到这个路径,请相应修改);
(3)将 C:\php\libmysql.dll 和 C:\php\ext\php_mysql.dll 复制到 C:\Windows\system32 下;
将 C:\php\php.ini-recommended 复制到 C:\Windows (Windows 2000 下为 C:\WINNT)并将改名为php.ini,
然后用记事本打开,利用记事本的查找功能搜索:
搜索“; Windows Extensions”并仅打开需要的模块以节省内存(去掉每个模块前的;号即可):
extension=php_gd2.dll
GD库支持,支持水印。
extension=php_mbstring.dll
支持phpMyAdmin
extension=php_mysql.dll
支持MySQL。
(4)配置 IIS 使其支持 PHP
在“控制面板”的“管理工具”中选择“Internet 服务管理器”,
然后在左侧选择你需要支持 PHP 的 Web 站点上单击右键选择“属性”,
在打开的“Web 站点属性”窗口的“ISAPI 筛选器”标签里找到并点击“添加”按钮,在弹出的“筛选器属性”窗口中的“筛选器名称”栏中输入:PHP,再将可执行文件指向 php5isapi.dll 所在路径,如:C:\php\php5isapi.dll。
打开“Web 站点属性”窗口的“主目录”标签,找到并点击“配置”按钮,在弹出的“应用程序配置”窗口中找到并点击“添加”按钮,在弹出的窗口中新增一个扩展名映射,扩展名为 .php ,单击“浏览”将可执行文件指向 php5isapi.dll 所在路径,如:C:\php\php5isapi.dll,然后一路确定即可。
再打开“Web 站点属性”窗口的“文档”标签,找到并点击“添加”按钮,向默认的 Web 站点启动文档列表中添加 index.php 项。您可以将 index.php 升到最高优先级,这样,访问站点时就会首先自动寻找并打开 index.php 文档。
确定 Web 目录的应用程序设置和执行许可中选择为纯脚本,然后关闭 Internet 信息服务管理器。
2003系统配置:在“Internet 服务管理器”左边的“WEB服务扩展”中设置:
ISAPI 扩展允许
开始-》运行-》输入“iisreset”,重启IIS。
在 IIS 根目录下新建一个 phpinfo.php,内容如下:
<?php
phpinfo();
?>
打开浏览器,输入:http://127.0.0.1/phpinfo.php,将显示当前服务器所支持 PHP 的全部信息。
三、安装 MySQL:
(1)官方下载:http://dev.mysql.com/downloads/mysql/5.2.html
custom
安装
Skip Sign-Up
Finish
Next
Standard Comfiguration
设置数据库密码
(重要)重新启动电脑!
四、安装 Zend Optimizer :(有需要时安装)
(1)官方下载:http://www.zend.com/products/zend_optimizer
(2)安装时只需选择Web服务器为iis,指定php.ini路径即可。
五、安装 phpMyAdmin:(用于管理MYSQL数据库,可选择)
下载 http://www.phpmyadmin.net,将其解压到站点根目录,
找到 ./libraties/config.default.php,做以下修改:
方案一:
搜索 $cfg['Servers'][$i]['auth_type'] 设置为config
搜索 $cfg['Servers'][$i]['user'] 用户名一般为root
搜索 $cfg['Servers'][$i]['password'] 设置MySQL的密码
打开浏览器,输入:http://127.0.0.1/phpMyAdmin/ ,若 IIS 和 MySQL 均已启动,即可浏览数据库内容。
(此设置允许任何人通过以上路径登录管理数据库,安全性极低)
方案二:
搜索 $cfg['Servers'][$i]['auth_type'] 设置为cookie
搜索 $cfg['Servers'][$i]['user'] 用户名一般为root
搜索 $cfg['PmaAbsoluteUri'] 访问路径,设置为http://127.0.0.1/phpmyadmin/
搜索 $cfg['blowfish_secret'] 这是cookie作用域,设置为127.0.0.1
(此设置只允许本机上登录,并且需要输入用户名密码才能登录,安全性极高)
-----------------------------------------------------------------------------------
至此所有安装完毕。以上配置在所有老版本软件中不一定有效,强烈推荐下载最新版本的软件。
C# 中对 Session 的“(string)”、“.ToString()”与“Convert.ToString”用法笔记
在实际操作当中,我们经常会遇到将 Session 的值转为 String 去判断是否为空或者判断是否有权限访问某页,这里的转换过程如果用得不恰当会抛出异常,给访问者带来不好的用户体验。这里我把它写成笔记,以供参考。
一、当 Session["a"] == null 时,
Session["a"].ToString() 抛出异常;
(string)Session["a"] 为 null;
Convert.ToString(Session["a"]) 为 ""。
二、当 Session["a"] == "" 时,
它们的值都为 ""。
所以,在判断 Session["a"] 是否有值时,如果用“.ToString()”,那么必需按照下面的格式与顺序写:
在这里,要注意判断的顺序:先判断是否为 null,再判断是否为 empty。如果 Session["a"] 为 null,则 Session["a"] != null 为 false 自然不会执行 .ToString(),也就不会报错;如果 Session["a"] 不为 null,则执行 .ToString() 也不会报错。
同理 if (Session["a"] == null || Session["a"].ToString() == "") 此句也合法可用。
用 .ToString() 的方法写格式比较固定,如果换成用 (string) 写,会比较自由:
if (Session["a"] != null && (string)Session["a"] != "")
这两种写法都是可行的,而且对 null 和 empty 的判断顺序没有关系。
最简单的方法就是用 Convert.ToString
不管 Session["a"] 为 null 还是 empty,Convert.ToString(Session["aaa"]) 都是 empty。