深度优先

这个家伙好懒,除了文章什么都没留下

0%

最开头,说明下文章转自:

https://www.cnblogs.com/landeanfen/p/5177176.html 点击打开链接

欢迎直接去看原创文章,原创比较精彩,这里只做个搬运工作!

一、跨域问题的由来

同源策略:出于安全考虑,浏览器会限制脚本中发起的跨站请求,浏览器要求JavaScript或Cookie只能访问同域下的内容。

正是由于这个原因,我们不同项目之间的调用就会被浏览器阻止。比如我们最常见的场景:WebApi作为数据服务层,它是一个单独的项目,我们的MVC项目作为Web的显示层,这个时候我们的MVC里面就需要调用WebApi里面的接口取数据展现在页面上。因为我们的WebApi和MVC是两个不同的项目,所以运行起来之后就存在上面说的跨域的问题。

二、跨域问题解决原理

CORS全称Cross-Origin Resource Sharing,中文全称跨域资源共享。它解决跨域问题的原理是通过向http的请求报文和响应报文里面加入相应的标识告诉浏览器它能访问哪些域名的请求。比如我们向响应报文里面增加这个Access-Control-Allow-Origin:http://url,就表示支持http://url里面的所有请求访问系统资源。其他更多的应用我们就不一一列举,可以去网上找找。

三、跨域问题解决细节

下面我就结合一个简单的实例来说明下如何使用CORS解决WebApi的跨域问题。

1、场景描述

我们新建两个项目,一个WebApi项目(下图中WebApiCORS),一个MVC项目(下图中Web)。WebApi项目负责提供接口服务,MVC项目负责页面呈现。如下:

其中,Web与WebApiCORS端口号分别为“27239”和“27221”。Web项目需要从WebApiCORSS项目里面取数据,很显然,两个项目端口不同,所以并不同源,如果使用常规的调用方法肯定存在一个跨域的问题。

简单介绍下测试代码,Web里面有一个HomeController

1
2
3
4
5
6
7
8
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
return View();
}
}

对应的Index.cshtml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
<script src="~/Content/jquery-1.9.1.js"></script>
<link href="~/Content/bootstrap/css/bootstrap.css" rel="stylesheet" />
<script src="~/Content/bootstrap/js/bootstrap.js"></script>
<script src="~/Scripts/Home/Index.js"></script>
</head>
<body>
测试结果:<div id="div_test">

</div>
</body>
</html>

Index.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var ApiUrl = "http://localhost:27221/";
$(function () {
$.ajax({
type: "get",
url: ApiUrl + "api/Charging/GetAllChargingData",
data: {},
success: function (data, status) {
if (status == "success") {
$("#div_test").html(data);
}
},
error: function (e) {
$("#div_test").html("Error");
},
complete: function () {

}

});
});

WebApiCORS项目里面有一个测试的WebApi服务ChargingController

1
2
3
4
5
6
7
8
9
10
11
12
public class ChargingController : ApiController
{
/// <summary>
/// 得到所有数据
/// </summary>
/// <returns>返回数据</returns>
[HttpGet]
public string GetAllChargingData()
{
return "Success";
}
}

配置WebApi的路由规则为通过action调用。WebApiConfig.cs文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API 路由
config.MapHttpAttributeRoutes();

config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}

2、场景测试

1)我们不做任何的处理,直接将两个项目运行起来。看效果如何

IE浏览器:

谷歌浏览器:

这个结果另博主也很吃惊,不做任何跨域处理,IE10、IE11竟然可以直接请求数据成功,而同样的代码IE8、IE9、谷歌浏览器却不能跨域访问。此原因有待查找,应该是微软动了什么手脚。

2)使用CORS跨域

首先介绍下CORS如何使用,在WebApiCORS项目上面使用Nuget搜索“microsoft.aspnet.webapi.cors”,安装第一个

然后在App_Start文件夹下面的WebApiConfig.cs文件夹配置跨域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
//跨域配置
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));

// Web API 路由
config.MapHttpAttributeRoutes();

config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}

我们暂定三个“*”号,当然,在项目中使用的时候一般需要指定对哪个域名可以跨域、跨域的操作有哪些等等。这个在下面介绍。

IE10、IE11

谷歌浏览器

IE8、IE9

这个时候又有新问题了,怎么回事呢?我都已经设置跨域了呀,怎么IE8、9还是不行呢?这个时候就有必要说说CORS的浏览器支持问题了。网上到处都能搜到这张图:

上图描述了CORS的浏览器支持情况,可以看到IE8、9是部分支持的。网上说的解决方案都是Internet Explorer 8 、9使用 XDomainRequest 对象实现CORS。是不是有这么复杂?于是博主各种百度寻找解决方案。最后发现在调用处指定 jQuery.support.cors = true; 这一句就能解决IE8、9的问题了。具体是在Index.js里面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
jQuery.support.cors = true;
var ApiUrl = "http://localhost:27221/";
$(function () {
$.ajax({
type: "get",
url: ApiUrl + "api/Charging/GetAllChargingData",
data: {},
success: function (data, status) {
if (status == "success") {
$("#div_test").html(data);
}
},
error: function (e) {
$("#div_test").html("Error");
},
complete: function () {

}
});
});

这句话的意思就是指定浏览器支持跨域。原来IE9以上版本的浏览器、谷歌、火狐等都默认支持跨域,而IE8、9却默认不支持跨域,需要我们指定一下。你可以在你的浏览器里面打印jQuery.support.cors看看。这样设置之后是否能解决问题呢?我们来看效果:

问题完美解决。至于网上说的CORS对IE8、9的解决方案XDomainRequest是怎么回事,有待实例验证。

3)CORS的具体参数设置。

上文我们使用

1
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));

这一句解决了跨域问题,上面说了,这种*号是不安全的。因为它表示只要别人知道了你的请求url,任何请求都可以访问到你的资源。这是相当危险的。所以需要我们做一些配置,限制访问权限。比如我们比较常见的做法如下:

配置方法一、在Web.Config里面(PS:这两张图源自:http://www.cnblogs.com/moretry/p/4154479.html

然后在WebApiConfig.cs文件的Register方法里面

配置方法二、如果你只想对某一些api做跨域,可以直接在API的类上面使用特性标注即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
[EnableCors(origins: "url", headers: "*", methods: "GET,POST,PUT,DELETE")]
public class ChargingController : ApiController
{
/// <summary>
/// 得到所有数据
/// </summary>
/// <returns>返回数据</returns>
[HttpGet]
public string GetAllChargingData()
{
return "Success";
}
}

作者:KwokKwok
链接:https://www.jianshu.com/p/be0ea8c04643
來源:简书

安装依赖组件

首先打开扩展和更新:

扩展和更新

联机查找下面的组件,然后安装,重启VS。

安装依赖组件

创建项目文件

作为应用的主程序。比如这里我就创建一个简单的项目,只有一个窗口:

创建一个简单的项目

创建一个打包项目

先右键解决方案,选择 添加-新建项目

创建打包项目

我这里就起名为 PackageDemo Installer

创建打包项目

另外,有些人可能会想这么多安装类型,怎么选。因为我们这里说Windows程序打包,想要输出 .exe.msi ,大概看一下介绍就能知道,第一个和第四个是合适的。这两个又该怎么选呢?那其实第四个就是对一些属性多了些引导,最终的项目结构和第一个是没有区别的。这里我们就选第一个。

配置

项目信息

配置项目信息,这里打开属性窗口。注意:不是在项目上右键-属性,而是选中项目后点击属性窗口查看:

查看项目属性

然后看各种对信息进行配置:

项目属性

这里对一些属性做下解释:

  1. 重要属性
    1. AuthorManufacturer ,分别是作者和制造商的意思,一般都写公司名。
    2. ProductName ,软件名。默认是项目名,影响到安装界面和安装目录。务必改掉。
    3. Version ,版本号,影响安装流程,后面会说。
    4. TargetPlatform ,意思很明显。表现层面上就是,决定你的安装目录是在 Program Files 还是 Program Files (x86) ,根据项目决定。
    5. RemovePreviousVersion ,是否移除之前的版本。务必改为True,不然你更新几次软件就会发现,电脑里多个版本都在安装着。
  2. 不重要的属性:
    1. InstallAllUsers ,用户权限默认值。这个在安装界面还可以重新设置。
    2. ManufacturerUrl ,公司官网。
    3. SupportUrlSupportPhone ,技术支持的网址和电话。
    4. Description ,软件描述。
    5. Title ,无用。一开始我以为它是安装界面的标题,但其实并不是,这个值默认和项目名一致,但你修改之后,在哪里也都看不到。所以无用。当然,现在我们还不能执行打包。还需要添加一些别的内容。

先看一下项目的文件系统

文件系统在项目刚创建的时候会默认打开,其他时候你也可以通过在项目上右键-View-文件系统打开。

文件系统

刚开始就会看到三个入口:

  1. Application Folder ,这个是你的应用安装之后,文件所处的目录。
  2. User's Desktop ,用户桌面,我们等下会需要在这里面放置一个快捷方式。
  3. User's Programs Menu ,用户的程序菜单。就是按Windows徽标键或者是屏幕左下角的Windows徽标,会出现的一些文件夹和快捷方式。

添加文件或文件夹

有时候我们会需要手动添加一些默认文件到安装目录里,比如一些默认配置、一些DLL等。接下来演示怎么创建文件夹和添加文件。

添加文件或文件夹

比如我重复使用上边的操作,创建了多级的文件夹,接下来我们可以通过添加文件,往里面添加一些icon图标,等下可以用作快捷方式的icon。

添加几个icon文件

添加可运行文件及其快捷方式

先创建项目输出文件(一般都是.exe文件),即快捷方式要指向的文件:

创建项目输出

项目输出配置

上面的流程也可以重复进行。针对多个项目创建多个项目输出,那样的话,就可以用启动不同的项目了。比如我们知道Git有GUI版本,也有命令行版本。就可以通过这种方式,创建多个输出文件。

添加完输出文件之后,我们就可以为这个输出创建快捷方式了:

创建输出快捷方式

比如这里创建出来的就是上面的那个 Shortcut ....balabala 的东西。这个快捷方式的名字需要修改,不然会直接在界面上显示这个名字。这里重命名一下即可。

输出文件(_这里的 主输出balabala _)是不能改名字的,它是对应的安装目录里的输出文件。比如我这个项目在安装后,安装目录里就会有一个 PackageDemo.exe 的文件。

也可以多次为这个输出创建快捷方式。这样的话,之后可以直接将快捷方式复制到别的入口文件夹里( User's Desktop / User's Programs Menu )。

这里我创建了多个快捷方式,并为它们改了不一样的名字。接下来,也为它们设置不一样的icon。

设置icon

先修改快捷方式的icon属性,这里默认为None,我们需要把它改为之前添加的icon图标。

修改图标

选择界面

在选择界面打开 Browse... ,找到之前添加的图标点击确认

选择完成

点击 OK 即可为快捷方式应用图标。其他的快捷方式也是一样的操作。

生成安装包并安装

在安装项目上右键,选择生成或重新生成。会执行打包操作。并会根据你的设置在项目的 DebugRelease 文件夹下生成一个 .msi 文件和一个 .exe 文件。用户可以使用这个安装包进行安装。

安装界面如下:

安装界面1

安装界面2

  1. 那个 任何人\只有我 的选项就是我们之前提到过的 InstallAllUsers 指定值。
  1. PackageDemo Installer 的问题,可以看出来,这个名字很不合适,那我们能不能改掉这个名字呢?这里就是之前提到过的,项目属性窗口中的 ProductName 属性,将该属性设置为软件名称即可。

再看下安装之后的效果:

安装效果

可以看到桌面和程序目录里各有一个快捷方式,它们的名字和图标也正是我们在文件系统设置的那样。

再来看看安装目录里的东西:

安装后文件夹

一些问题

版本号问题

假设,你当前电脑上已经使用一个安装包安装了1.0.0版本的软件:

此时你再次点击同样的安装包:

同样的安装包

如果,你对项目做了一些修改后重新打包,却没修改版本号:

相同版本号,不同的内容

如果,你对项目做了一些修改后,也增加了版本号:

修改版本号

这样是可以正常安装的。并且如果你设置了移除旧版本,也会同时卸载掉旧版本软件。

生成失败

有时你执行了生成或重新生成却发现左下角提示生成失败

生成失败

然后打开错误列表,如果有错误的话,去修改错误(警告等是不会导致失败的,只查看错误就可以)。可是,有时候,会出现这种情况:

生成失败却没有提示任何错误

明明没有一个错误,却导致生成失败了?

这种问题,基本上都是文件系统引用到的文件位置发生了改变。就是说,你在上边执行的添加文件,其实只是把你电脑上的文件地址保存了起来,之后如果你的文件被删了或是换了位置,那之前添加的文件引用自然就会失效。这时候去仔细查看一下文件系统。

比如我把几个图标文件移动到别的文件夹之后:

文件引用错误

这时候,把错误的引用删掉,重新将文件添加进来即可。注意:icon文件修改后,引用icon的快捷方式也需要修改icon路径。

一个建议

在安装项目内创建一个文件夹,专门用于放置安装项目所依赖的文档、图标等,避免引用的文件移动后还需要重新设置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
public class BLDateHelper
{
#region 年份,返回ArrayList类型
public ArrayList Year()
{
ArrayList arraylist = new ArrayList(210);
for (int i = 1901; i < 2101; i++)
{

arraylist.Add(i);
}
return arraylist;
}
#endregion

#region 公历月份,返回ArrayList类型
public ArrayList Month()
{
ArrayList arraylist = new ArrayList();
for (int i = 1; i <= 12; i++)
{
arraylist.Add(i);
}
return arraylist;
}
#endregion

#region 根据年月返回公历当月的天数
public int GetMonthCount(int year, int month)
{
int count = DateTime.DaysInMonth(year, month);
return count;
}
#endregion

#region 根据年月返回当年当月第一天星期几
//2000-1-2为周日
//返回以0为周日
public int FirstDayOfWeekOfMonth(int year, int month)
{
DateTime jztime = new DateTime(2000, 1, 2);
DateTime newtime = new DateTime(year, month, 1);
TimeSpan ts;
int dayofweek = 0;
if (jztime < newtime)
{
ts = newtime - jztime;
dayofweek = ts.Days % 7;
return dayofweek;
}
else
{
ts = jztime - newtime;
dayofweek = (ts.Days) % 7;
return (7 - dayofweek) % 7;
}
}
#endregion

#region 根据年月日算星期几,返回string类型,方法二:(简捷)以一个基准日期,两日期相减算法
//方法三
//以一个基准日期,两日期相减算法
//根据年月日算星期几,返回string类型
//2000-1-1为星期六
public string GetWeekOfDay(int year, int month, int day)
{
//int runnian=0;
DateTime jztime = new DateTime(2000, 1, 1);
DateTime newtime = new DateTime(year, month, day);
TimeSpan chatime;
int week;
string weekstr = "";
if (jztime <= newtime)
{
chatime = newtime - jztime;
week = (chatime.Days + 1) % 7;
switch (week)
{
case 1:
weekstr = "星期六";
break;
case 2:
weekstr = "星期日";
break;
case 3:
weekstr = "星期一";
break;
case 4:
weekstr = "星期二";
break;
case 5:
weekstr = "星期三";
break;
case 6:
weekstr = "星期四";
break;
case 0:
weekstr = "星期五";
break;
}
}
else
{
chatime = jztime - newtime;
week = (chatime.Days + 1) % 7;
switch (week)
{
case 1:
weekstr = "星期六";
break;
case 2:
weekstr = "星期五";
break;
case 3:
weekstr = "星期四";
break;
case 4:
weekstr = "星期三";
break;
case 5:
weekstr = "星期二";
break;
case 6:
weekstr = "星期一";
break;
case 0:
weekstr = "星期日";
break;
}
}
return weekstr;

}
#endregion

#region 根据公历日期返回农历日
public string GetNLMonth(int year, int month, int day)
{
string[] monthname = { "正月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "腊月" };
ChineseLunisolarCalendar calendar = new ChineseLunisolarCalendar();
DateTime datetime = new DateTime(year, month, day);

int nlyear = calendar.GetYear(datetime);
int nlmonth = calendar.GetMonth(datetime);

//判断是否有闰月 ,leap=0即没有闰月
int leapmonth = calendar.GetLeapMonth(nlyear);
if (leapmonth > 0)
{
if (leapmonth <= nlmonth)
{
nlmonth--;
}
}
return monthname[nlmonth - 1].ToString();
}
#endregion

#region 根据公历日期返回农历日
public string GetNLDay(int year, int month, int day)
{
string[] nstr1 = { "一", "二", "三", "四", "五", "六", "七", "八", "九", "十" };
string[] nstr2 = { "初", "十", "廿", "卅" };
string[] monthname = { "正月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "腊月" };
ChineseLunisolarCalendar calendar = new ChineseLunisolarCalendar();
DateTime datetime = new DateTime(year, month, day);

int nlyear = calendar.GetYear(datetime);
int nlmonth = calendar.GetMonth(datetime);
int nlday = calendar.GetDayOfMonth(datetime);

//判断是否有闰月 ,leap=0即没有闰月
int leapmonth = calendar.GetLeapMonth(nlyear);
if (leapmonth > 0)
{
if (leapmonth <= nlmonth)
{
nlmonth--;
}
}
if (nlday == 1)
{
return monthname[nlmonth - 1].ToString();
}
else
{
if (nlday > 1 && nlday <= 10)
{
return nstr2[0].ToString() + nstr1[nlday - 1].ToString();
}
else if (nlday > 10 && nlday < 20)
{
return nstr2[1].ToString() + nstr1[nlday % 10 - 1].ToString();
}
else if (nlday == 20)
{
return "二十";
}
else if (nlday > 20 && nlday < 30)
{
return nstr2[2].ToString() + nstr1[nlday % 10 - 1].ToString();
}
else if (nlday == 30)
{
return "三十";
}
else
{
return "卅一";
}
}

}
#endregion

#region 阳历转化为农历,返回string类型
//ChineseLunisolarCalendar类能实现的日期为1901-2-19——2101-1-28
//阳历转化为农历,返回string类型
//以公元前2997年为中国历史上第一个甲子年
public string GetNLYear(int year, int month, int day)
{
string datestr = "";
string[] gan = { "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" };
string[] zhi = { "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" };
string[] shengxiao = { "鼠", "牛", "虎", "免", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪" };
ChineseLunisolarCalendar calendar = new ChineseLunisolarCalendar();
DateTime date = new DateTime(year, month, day);

int nlyear = calendar.GetYear(date);
int nlmonth = calendar.GetMonth(date);
int nlday = calendar.GetDayOfMonth(date);

//判断是否有闰月 ,leap=0即没有闰月
int leapmonth = calendar.GetLeapMonth(nlyear);
if (leapmonth > 0)
{
if (leapmonth <= nlmonth)
{
nlmonth--;
}
}

//确定年份,基准1804为甲子年,鼠年
//天干年
string zy = "";
//地支年
string dy = "";
//生肖年
string sxnian = "";
if (nlyear > 3)
{
int zhiyear = (nlyear - 4) % 10;
int diyear = (nlyear - 4) % 12;
zy = gan[zhiyear];
dy = zhi[diyear];
sxnian = shengxiao[diyear];
}

//转化的最终农历年
datestr = zy + dy + "(" + nlyear + ")" + "年" + " 生肖:" + sxnian;

return datestr;
}
#endregion


public string GetNL(int year, int month, int day)
{
string nlDay = GetNLDay(year, month, day);
string nlMonth = GetNLMonth(year, month, day);
string nlYear = GetNLYear(year, month, day);
return nlYear + " " + nlMonth + " " + nlDay;
}
}
}