面试·网站后台开发工程师·总结

关于2018年3月9日面试某公司网站后台开发工程师的一些总结。

面试问题总结

面试官非常nice,可能是因为之前通过同学跟他有过一些间接交流,所以开场时问了我:“我让XXX告诉你去学习一下.NET Core,你学的怎么样了。”
瞬间整个人就不那么紧张了。之后面试官首先问了我一些我目前主要使用的C#桌面软件开发的一些知识,之后在逐渐的把问题转到.NET Core,从中可以感觉得出面试官对于基础知识即为擅长,问的问题大量的都是非常细节性的,由于我在.NET Core上并没有付出很多的学习时间,而且主要是“自定向下”的学习,主要学习怎么使用,这些细节就了解的不那么清楚了,所以整个面试确实有不少问题没能回答得上来。
下面是具体没能答上来问题的具体分析。

桌面开发

Winform 多线程状态下应该怎样保持界面响应

当时回答了可以使用.Net Framework 4.5版本以上支持的语法糖await\asnyc来进行多线程请求,或者是新开线程完成操作,或者使用Application.DoEvent()这样的函数强行保持界面响应。
当时应该是有些紧张,没有准确get到面试官真正想要问的问题,事后思考感觉面试官真正想问的应该是使用委托解决方法的跨线程调用问题这种类型的委托问题,所以这道题也算是没有回答好。

数据库

数据库横表、纵表转换

这道题确实是忘记了大学学习的知识,也没反应过来横纵表转换到底是什么概念,下面直接写一个例子吧。

横表结构: Achievement

ID姓名语文数学英语
1张三809070
2李四908595
3王五887590

转换后的表结构

ID姓名科目成绩
1张三语文80
2张三数学90
3张三英语70
4李四语文90
5李四数学80
6李四英语99
7王五语文85
8王五数学96
9王五英语88
1
2
3
4
SELECT 姓名,'语文' AS 科目,语文 AS 成绩 FROM Achievement UNION ALL
SELECT 姓名,'数学' AS 科目,数学 AS 成绩 FROM Achievement UNION ALL 
SELECT 姓名,'英语' AS 科目,英语 AS 成绩 FROM Achievement
ORDER BY 姓名,科目 DESC;

.NET Core

下面题目中的一些.NET Core的细节,我会引用来自本人购买的 张剑桥 先生的《ASP.NET Core 跨平台开发从入门到实战》一书中的内容,如果希望获得更多的知识请直接在各大平台购买本书,若侵犯了您的权利,请联系删除。

.NET Core 程序增加中间件在什么位置

在 ASP.NET Core 中,你可以使用中间件构建你的请求处理管道。ASP.NET Core 中间件为一个HttpContext 执行异步逻辑,然后按顺序调用下一个中间件或者直接终止请求。一般来说,要使用一个中间件,只需在Configure方法里调用 IApplicationBuilder 上一个对应的扩展方法即可。

静态文件访问开启

为了能够使用静态文件服务,必须配置中间件,把静态文件中间件加入到管道内。静态文件中间件可通过下述方法来配置:在项目中增加 Microsoft.AspNetCore.StaticFiles包依赖,然后从 Startup.Configure 中调用.UseStaticFiles扩展方法:

1
2
3
4
5
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseStaticFiles();
}

配置使用Session

与上面的静态文件相同,需要首先依赖 Microsoft.AspNetCore.Session 包,然后从Startup.Configure 中调用.UseSession方法。

1
2
3
4
5
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseSession();
}

EF Core如何启用懒加载

EF6中是默认开启懒加载的,可以通过修改配置文件来进行修改,而到了EF Core中,则可以在 DbContext 的 OnConfiguring 方法中添加对 UseLazyLoadingProxies() 扩展方法调用即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class WayneContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var sqlConnectionStringBuilder = new SqlConnectionStringBuilder {
DataSource = "****",
InitialCatalog = "Wayne",
UserID = "sa",
Password = "sa"
};

optionsBuilder.UseSqlServer(sqlConnectionStringBuilder.ConnectionString);

optionsBuilder.UseLazyLoadingProxies();

base.OnConfiguring(optionsBuilder);
}
}

Asp.NET Core的热部署是怎么实现的

以MVC模板为例,其实是在 Program 类中的 CreateWebHostBuilder 方法中实现的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;

namespace TestCore
{
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
}

第十四行,WebHost.CreateDefaultBuilder(args)方法中巨硬封装了读取配置文件的操作。F12反编译转到源码。

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
/// <summary>
/// Initializes a new instance of the <see cref="T:Microsoft.AspNetCore.Hosting.WebHostBuilder" /> class with pre-configured defaults.
/// </summary>
/// <remarks>
/// The following defaults are applied to the returned <see cref="T:Microsoft.AspNetCore.Hosting.WebHostBuilder" />:
/// use Kestrel as the web server and configure it using the application's configuration providers,
/// set the <see cref="P:Microsoft.AspNetCore.Hosting.IHostingEnvironment.ContentRootPath" /> to the result of <see cref="M:System.IO.Directory.GetCurrentDirectory" />,
/// load <see cref="T:Microsoft.Extensions.Configuration.IConfiguration" /> from 'appsettings.json' and 'appsettings.[<see cref="P:Microsoft.AspNetCore.Hosting.IHostingEnvironment.EnvironmentName" />].json',
/// load <see cref="T:Microsoft.Extensions.Configuration.IConfiguration" /> from User Secrets when <see cref="P:Microsoft.AspNetCore.Hosting.IHostingEnvironment.EnvironmentName" /> is 'Development' using the entry assembly,
/// load <see cref="T:Microsoft.Extensions.Configuration.IConfiguration" /> from environment variables,
/// load <see cref="T:Microsoft.Extensions.Configuration.IConfiguration" /> from supplied command line args,
/// configures the <see cref="T:Microsoft.Extensions.Logging.ILoggerFactory" /> to log to the console and debug output,
/// enables IIS integration,
/// and enables the ability for frameworks to bind their options to their default configuration sections.
/// </remarks>
/// <param name="args">The command line args.</param>
/// <returns>The initialized <see cref="T:Microsoft.AspNetCore.Hosting.IWebHostBuilder" />.</returns>
public static IWebHostBuilder CreateDefaultBuilder(string[] args)
{
IWebHostBuilder hostBuilder = new WebHostBuilder().UseKestrel((Action<WebHostBuilderContext, KestrelServerOptions>)((builderContext, options) => options.Configure((IConfiguration)builderContext.Configuration.GetSection("Kestrel")))).UseContentRoot(Directory.GetCurrentDirectory()).ConfigureAppConfiguration((Action<WebHostBuilderContext, IConfigurationBuilder>)((hostingContext, config) =>
{
IHostingEnvironment hostingEnvironment = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", true, true).AddJsonFile(string.Format("appsettings.{0}.json", (object)hostingEnvironment.EnvironmentName), true, true);
if (hostingEnvironment.IsDevelopment())
{
Assembly assembly = Assembly.Load(new AssemblyName(hostingEnvironment.ApplicationName));
if (assembly != (Assembly)null)
config.AddUserSecrets(assembly, true);
}
config.AddEnvironmentVariables();
if (args == null)
return;
config.AddCommandLine(args);
}))
.ConfigureLogging((Action<WebHostBuilderContext, ILoggingBuilder>)((hostingContext, logging) =>
{
logging.AddConfiguration((IConfiguration)hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
}))
.UseIISIntegration().UseDefaultServiceProvider((Action<WebHostBuilderContext, ServiceProviderOptions>)((context, options) => options.ValidateScopes = context.HostingEnvironment.IsDevelopment()));
if (args != null)
hostBuilder.UseConfiguration((IConfiguration)new ConfigurationBuilder().AddCommandLine(args).Build());
return hostBuilder;
}

第23行 中

1
config.AddJsonFile("appsettings.json", true, true).AddJsonFile(string.Format("appsettings.{0}.json", (object)hostingEnvironment.EnvironmentName), true, true);

继续查看config扩展方法AddJsonFile的源码

1
2
3
4
5
6
7
8
9
10
11
12
13
/// <summary>
/// Adds the JSON configuration provider at <paramref name="path" /> to <paramref name="builder" />.
/// </summary>
/// <param name="builder">The <see cref="T:Microsoft.Extensions.Configuration.IConfigurationBuilder" /> to add to.</param>
/// <param name="path">Path relative to the base path stored in
/// <see cref="P:Microsoft.Extensions.Configuration.IConfigurationBuilder.Properties" /> of <paramref name="builder" />.</param>
/// <param name="optional">Whether the file is optional.</param>
/// <param name="reloadOnChange">Whether the configuration should be reloaded if the file changes.</param>
/// <returns>The <see cref="T:Microsoft.Extensions.Configuration.IConfigurationBuilder" />.</returns>
public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange)
{
return builder.AddJsonFile((IFileProvider) null, path, optional, reloadOnChange);
}

形参中的第四个参数为

1
/// <param name="reloadOnChange">Whether the configuration should be reloaded if the file changes.</param>

当这个参数被设置为 true 时即可实现热更新。

怎样修改绑定的地址

在 Program 类的 CreateWebHostBuilder 中增加 UseUrls 方法的调用

1
2
3
4
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseUrls("http://localhost:5001")
.UseStartup<Startup>();

更改实体类后怎样同步更改到数据库

主要要使用EF的cli命令
提交更改

1
dotnet ef migrations Add InitialCreate

同步到数据库

1
dotnet ef database update

回滚到之前的某一次提交

1
dotnet ef migrations update InitialCreate

回滚后同步代码回滚

1
dotnet ef migrations remove

将更改生成SQL脚本(一般是为了方便部署到正式环境)

1
dotnet ef migrations script