public class BaseXXXContext: XXXContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
var envName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
IConfigurationRoot configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false)
.AddJsonFile($"appsettings.{envName}.json", optional: false)
.Build();
optionsBuilder.UseSqlServer(configuration.GetConnectionString("XXXContext"));
}
}
}
]]>
旧代码:
public class TraceExtension : SoapExtension
{
Stream _oldStream;
Stream _newStream;
public override Stream ChainStream(Stream stream)
{
_oldStream = stream;
_newStream = new MemoryStream();
return _newStream;
}
public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
{
return null;
}
public override object GetInitializer(Type WebServiceType)
{
return null;
}
public override void Initialize(object initializer)
{
}
public override void ProcessMessage(SoapMessage message)
{
switch (message.Stage)
{
case SoapMessageStage.BeforeSerialize:
//TestRequest(message);
break;
case SoapMessageStage.AfterSerialize:
WriteRequest(message);
break;
case SoapMessageStage.BeforeDeserialize:
WriteResponse(message);
break;
case SoapMessageStage.AfterDeserialize:
break;
default:
throw new Exception("invalidstage");
}
}
public void WriteRequest(SoapMessage message)
{
try
{
_newStream.Position = 0;
TextReader reader = new StreamReader(_newStream);
string methodName = message.MethodInfo.ToString();
string reqLog = reader.ReadToEnd();
//@@ Async log
Task t = Task.Factory.StartNew(() =>
{
try
{
WebSvcLogger.Logger.Information(string.Format("API - \"{0}\" Request:\r\n{1}", methodName, reqLog));
}
catch
{
//Log Failed
}
});
}
catch
{
//Log Failed
}
finally
{
_newStream.Position = 0;
Copy(_newStream, _oldStream);
}
}
public void WriteResponse(SoapMessage message)
{
try
{
Copy(_oldStream, _newStream);
_newStream.Position = 0;
TextReader reader = new StreamReader(_newStream);
string methodName = message.MethodInfo.ReturnType.FullName;
string respLog = reader.ReadToEnd();
//Async run
Task t = Task.Factory.StartNew(() =>
{
WebSvcLogger.Logger.Information(string.Format("API - \"{0}\" Response:\r\n{1}", methodName, respLog));
});
}
catch
{
//Log Failed
}
finally
{
_newStream.Position = 0;
}
}
void Copy(Stream from, Stream to)
{
TextReader reader = new StreamReader(from);
TextWriter writer = new StreamWriter(to);
writer.WriteLine(reader.ReadToEnd());
writer.Flush();
}
}
[AttributeUsage(AttributeTargets.Method)]
public class TraceExtensionAttribute : SoapExtensionAttribute
{
private int priority;
public override Type ExtensionType
{
get { return typeof(TraceExtension); }
}
public override int Priority
{
get { return priority; }
set { priority = value; }
}
}
新代码:
public class HttpProtocol : IClientMessageInspector
{
private readonly string _serviceName;
public HttpProtocol(string serviceName)
{
_serviceName = serviceName;
}
public void AfterReceiveReply(ref Message reply, object correlationState)
{
var buffer = reply.CreateBufferedCopy(Int32.MaxValue);
reply = buffer.CreateMessage();
WriteResponse(buffer.CreateMessage().CreateBufferedCopy(Int32.MaxValue));
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
var buffer = request.CreateBufferedCopy(Int32.MaxValue);
request = buffer.CreateMessage();
WriteRequest(buffer.CreateMessage().CreateBufferedCopy(Int32.MaxValue));
return null;
}
public Message WriteRequest(MessageBuffer buffer)
{
Message msg = buffer.CreateMessage();
StringBuilder sb = new StringBuilder();
sb.Append(msg.ToString());
string reqLog = sb.ToString();
//@@ Async log
Task t = Task.Factory.StartNew(() =>
{
try
{
WebSvcLogger.Logger.Information(string.Format("API - \"{0}\" Request:\r\n{1}", _serviceName, reqLog));
}
catch
{
//Log Failed
}
});
return buffer.CreateMessage();
}
public Message WriteResponse(MessageBuffer buffer)
{
Message msg = buffer.CreateMessage();
StringBuilder sb = new StringBuilder();
sb.Append(msg.ToString());
string respLog = sb.ToString();
//Async run
Task t = Task.Factory.StartNew(() =>
{
WebSvcLogger.Logger.Information(string.Format("API - \"{0}\" Response:\r\n{1}", _serviceName, respLog));
});
return buffer.CreateMessage();
}
private static Message Clone(Message message)
{
return message.CreateBufferedCopy(int.MaxValue).CreateMessage();
}
}
public class TraceMessageBehavior : IEndpointBehavior
{
private readonly string _serviceName;
public TraceMessageBehavior(string serviceName)
{
_serviceName = serviceName;
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{ }
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.ClientMessageInspectors.Add(new HttpProtocol(_serviceName));
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{ }
}
旧方法:
SearchServiceBinding client = new SearchServiceBinding();
client.Url = "http://localhost/";
//Set Basic Auth Authorization
client.Credentials = new NetworkCredential(config.Username, config.Password);
// Send the request
var resp = client.service(req);
return resp;
新方法:
var binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
var address = "http://localhost/";
ServicePortTypeClient client = new ServicePortTypeClient(binding, address);
client.Endpoint.EndpointBehaviors.Add(new TraceMessageBehavior("Search"));
//Set Basic Auth Authorization
client.ClientCredentials.UserName.UserName = config.Username;
client.ClientCredentials.UserName.Password = config.Password;
// Send the request
var resp = await client.serviceAsync(req);
return resp;
]]>axios的get请求报错是因为底层的实现方式跟jquery的ajax有所区别,jquery ajax的headers默认设置的content-type为application/x-www-form-urlencoded,axios默认为 application/json,而且axios会发送一个preflight来判断api是否可用,解决方式是修改axios的get请求的content-type,修改代码如下:
axios.interceptors.request.use(
config => {
if (config.method === 'get') {
config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
return config
}})
]]>using System.Data.Entity.ModelConfiguration.Configuration;
using System.Linq;
using System.Collections.Generic;
namespace TestCase.EntityFramework
{
public class TestCaseDBConfig : DbConfiguration
{
private static string EFFoldPath = "";
public TestCaseDBConfig() : base()
{
SetProviderServices("System.Data.SqlClient", System.Data.Entity.SqlServer.SqlProviderServices.Instance);
EFFoldPath = AppDomain.CurrentDomain.BaseDirectory + "App_Data\\EFCache";
if (!Directory.Exists(EFFoldPath))
Directory.CreateDirectory(EFFoldPath);
TestCaseDbModelStore cachedDbModelStore = new TestCaseDbModelStore(EFFoldPath);
IDbDependencyResolver dependencyResolver = new SingletonDependencyResolver<DbModelStore>(cachedDbModelStore);
AddDependencyResolver(dependencyResolver);
}
private class TestCaseDbModelStore : DefaultDbModelStore
{
public TestCaseDbModelStore(string location)
: base(location)
{ }
public override XDocument TryGetEdmx(Type contextType)
{
return LoadXml2(contextType, XDocument.Load);
}
private void GetConceptualAssociationNames(List<System.Data.Entity.Core.Metadata.Edm.AssociationType> lstAssociationTypes, List<string> lstNames)
{
int oldCount = lstNames.Distinct().ToList().Count;
foreach (var association in lstAssociationTypes)
{
if (association.AssociationEndMembers != null && association.AssociationEndMembers.Count > 0)
{
var isAssociaEsixt = association.AssociationEndMembers.Where(a => lstNames.Contains(a.GetEntityType().Name)).FirstOrDefault() != null;
if (isAssociaEsixt)
{
if (!lstNames.Contains(association.Name))
lstNames.Add(association.Name);
foreach (var endMember in association.AssociationEndMembers)
{
if (!lstNames.Contains(endMember.GetEntityType().Name))
lstNames.Add(endMember.GetEntityType().Name);
}
}
}
}
if (oldCount != lstNames.Distinct().Count())
{
GetConceptualAssociationNames(lstAssociationTypes, lstNames);
}
}
public override void Save(Type contextType, DbModel model)
{
if (contextType.GenericTypeArguments != null && contextType.GenericTypeArguments.Length > 0)
{
string name = contextType.GenericTypeArguments[0].Name;
List<string> storeModelNames = new List<string>();
storeModelNames.Add(name);
storeModelNames.Add("Entities");
#region StoreModel
List<string> storeModelAssociates = new List<string>();
if (model.StoreModel.AssociationTypes != null && model.StoreModel.AssociationTypes.Count() > 0)
{
GetConceptualAssociationNames(model.StoreModel.AssociationTypes.ToList(), storeModelNames);
var removedStoreAssociates = model.StoreModel.AssociationTypes.Where(a => !storeModelNames.Contains(a.Name)).ToList();
foreach (var removedAssociate in removedStoreAssociates)
{
var tmp = model.StoreModel.AssociationTypes.Where(a => a.Name == removedAssociate.Name).FirstOrDefault();
if (tmp != null)
{
model.StoreModel.RemoveItem(tmp);
}
}
}
storeModelNames = storeModelNames.Distinct().ToList();
var removedStoreModels = model.StoreModel.EntityTypes.Where(a => !storeModelNames.Contains(a.Name)).ToList();
foreach (var removedStoreModel in removedStoreModels)
{
var tmp = model.StoreModel.EntityTypes.Where(a => a.Name == removedStoreModel.Name).FirstOrDefault();
if (tmp != null)
{
model.StoreModel.RemoveItem(tmp);
}
}
var removeEntitySetBase = model.StoreModel.Container.BaseEntitySets.Where(a => !storeModelNames.Contains(a.ElementType.Name)).ToList();
foreach (var removedStoreModel in removeEntitySetBase)
{
var tmp = model.StoreModel.Container.BaseEntitySets.Where(a => a.Name == removedStoreModel.Name).FirstOrDefault();
if (tmp != null)
{
model.StoreModel.Container.RemoveEntitySetBase(tmp);
}
}
#endregion
#region ConceptualModel
List<string> conceptualAssociates = new List<string>();
if (model.ConceptualModel.AssociationTypes != null && model.ConceptualModel.AssociationTypes.Count() > 0)
{
GetConceptualAssociationNames(model.ConceptualModel.AssociationTypes.ToList(), storeModelNames);
var removedStoreAssociates = model.ConceptualModel.AssociationTypes.Where(a => !storeModelNames.Contains(a.Name)).ToList();
foreach (var removedAssociate in removedStoreAssociates)
{
var tmp = model.ConceptualModel.AssociationTypes.Where(a => a.Name == removedAssociate.Name).FirstOrDefault();
if (tmp != null)
{
model.ConceptualModel.RemoveItem(tmp);
}
}
}
storeModelNames = storeModelNames.Distinct().ToList();
var conceptualStoreModels = model.ConceptualModel.EntityTypes.Where(a => !storeModelNames.Contains(a.Name)).ToList();
foreach (var removedStoreModel in conceptualStoreModels)
{
var tmp = model.ConceptualModel.EntityTypes.Where(a => a.Name == removedStoreModel.Name).FirstOrDefault();
if (tmp != null)
{
model.ConceptualModel.RemoveItem(tmp);
}
}
var removeConcepEntitySetBase = model.ConceptualModel.Container.BaseEntitySets.Where(a => !storeModelNames.Contains(a.ElementType.Name)).ToList();
foreach (var removedStoreModel in removeConcepEntitySetBase)
{
var tmp = model.ConceptualModel.Container.BaseEntitySets.Where(a => a.Name == removedStoreModel.Name).FirstOrDefault();
if (tmp != null)
{
model.ConceptualModel.Container.RemoveEntitySetBase(tmp);
}
}
#endregion
#region Mapping
if (model.ConceptualToStoreMapping != null && model.ConceptualToStoreMapping.EntitySetMappings != null && model.ConceptualToStoreMapping.EntitySetMappings.Count() > 0)
{
List<System.Data.Entity.Core.Mapping.EntitySetMapping> lstEntitySetMappings = new List<System.Data.Entity.Core.Mapping.EntitySetMapping>();
bool isMappingExists = false;
foreach (var mapping in model.ConceptualToStoreMapping.EntitySetMappings)
{
isMappingExists = false;
if (mapping.EntityTypeMappings != null && mapping.EntityTypeMappings.Count > 0)
{
foreach (var subMapping in mapping.EntityTypeMappings)
{
if (subMapping.EntityTypes != null && subMapping.EntityTypes.Count > 0)
{
foreach (var ef in subMapping.EntityTypes)
{
if (!storeModelNames.Contains(ef.Name))
{
lstEntitySetMappings.Add(mapping);
isMappingExists = true;
break;
}
}
}
if (isMappingExists)
break;
}
}
}
lstEntitySetMappings = lstEntitySetMappings.Distinct().ToList();
if (lstEntitySetMappings.Count > 0)
{
foreach (var tmpMapping in lstEntitySetMappings)
{
var tmp = model.ConceptualToStoreMapping.EntitySetMappings.Where(a => a == tmpMapping).FirstOrDefault();
if (tmp != null)
{
model.ConceptualToStoreMapping.RemoveSetMapping(tmp);
}
}
}
}
#endregion
}
using (var writer = XmlWriter.Create(GetFilePath2(contextType), new System.Xml.XmlWriterSettings { Indent = true }))
{
EdmxWriter.WriteEdmx(model, writer);
}
}
public string GetFilePath2(Type contextType)
{
var filename = (contextType.GenericTypeArguments.Length > 0 ? contextType.GenericTypeArguments[0].Name : contextType.FullName) + ".edmx";
string path = Path.Combine(EFFoldPath, filename);
return path;
}
public override DbCompiledModel TryLoad(Type contextType)
{
string path = GetFilePath2(contextType);
if (File.Exists(path))
{
DateTime lastWriteTime = File.GetLastWriteTimeUtc(path);
DateTime lastWriteTimeDomainAssembly = File.GetLastWriteTimeUtc(contextType.Assembly.Location);
if (lastWriteTimeDomainAssembly > lastWriteTime)
{
File.Delete(path);
}
}
return LoadXml2(contextType, reader => {
var defaultSchema = GetDefaultSchema(contextType);
return EdmxReader.Read(reader, defaultSchema);
});
}
internal T LoadXml2<T>(Type contextType, Func<XmlReader, T> xmlReaderDelegate)
{
var filePath = GetFilePath2(contextType);
if (!File.Exists(filePath))
{
return default(T);
}
if (!FileIsValid2(contextType, filePath))
{
File.Delete(filePath);
return default(T);
}
using (var reader = XmlReader.Create(filePath))
{
return xmlReaderDelegate(reader);
}
}
public bool FileIsValid2(Type contextType, string filePath)
{
var contextCreated =
File.GetLastWriteTimeUtc(contextType.Assembly.Location);
var storeCreated = File.GetLastWriteTimeUtc(filePath);
return storeCreated >= contextCreated;
}
}
}
}
]]>前端使用vuejs加载数据,解决办法就是不用等到所有数据加载完成,类似下载功能一样,下载一部分就加载一部分数据,我们在onDownloadProgress里面返回已经下载的数据就行了,如下:
调用接口:
search (keywords, doAction) {
cancelRequest()
const data = {
keywords: keywords
}
return new Promise((resolve, reject) => {
axios({
method: 'POST',
url: 'search',
data: data,
dataType: 'json',
cancelToken: new CancelToken(function executor (c) {
cancel = c
}),
onDownloadProgress (progress) {
doAction(progress.currentTarget.response)
}
})
.then(response => {
// resolve(response)
})
.catch(() => {})
})
}
处理数据:
hotel.search(key, function (json) {
// 返回的数据可能不完整,所以需要替换一些特殊字符,让整个字符串可以转成json
var willLoadJsonStr = json
.replace('{"status":"Success","message":"","data":{"hotels":[', '')
.replace(']}}', '')
// 分割字符串,让每一段字符串都是一个对象
var destArr = willLoadJsonStr.split('},{')
for (var di = 0; di < destArr.length; di++) {
var destStr = (di == 0 ? '' : '{') + destArr[di] + '}'
if (root.isJSON(destStr)) {
let destJson = JSON.parse(destStr)
// 跳过已经添加的数据
if (root.lstProperties.filter(a => a.hotelId == destJson.hotelId).length > 0) {
continue
}
root.lstProperties.push(destJson)
root.setDestSectionElement(key, destJson)
}
}
})
.then(function (json) {
// console.log(json)
})
.catch(error => {
});
这样处理之后不管api返回多大的数据,页面都可以很快的响应。
]]>services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => {
options.Authority = "http://192.168.1.1"; // 这里要是具体访问的域名
options.Audience = "api";
options.RequireHttpsMetadata = false;
});
重新发布后删除根目录的 tempkey.rsa 文件,重启IIS即可。
]]>semantic-ui的dropdown源码在/semantic/src/definitions/modules/dowpdown.js.
我们在第805行添加处理字符串的代码:
// 上一个uedbet下载条件的html标签对当前字符串有影响,需要清理上一个的结果
var originalHtml = $(this).html().toString()
.replace(/<strong>/g, '')
.replace(/<\/strong>/g, '');
// 忽略大小和html标签,替换uedbet下载的字符串,并加上特殊的html,我这里用的是strong
var newHtml = originalHtml.replace(new RegExp(searchTerm + "(?![^<>]*>)", "ig"), function(e){
return '<strong>' + e + '</strong>';
});
// 替换当前的html,由于添加了strong标签,所以下一次uedbet下载需要清理掉对应的标签
$(this).html(newHtml);
注意第794行的条件,if( module.has.query() ),也就是清空uedbet下载内容后,这部分为空,之前的加粗标签在显示所有下拉选项的时候并没有被清理,所以需要在之后添加else处理没有uedbet下载内容的情况。
// 方法很简单,遍历所有item并删掉strong标签即可
$item
.each(function(){
var defaultText = $(this).html().toString()
.replace(/<strong>/g, '')
.replace(/<\/strong>/g, '');
$(this).html(defaultText)
return true;
})
;
另外,由于项目中dropdown进行了分组显示,uedbet下载结果中如果itemgroup没有对应的内容,需要对itemgroup进行隐藏处理。
$item
.not(results)
.length === $item.length
? $item.parent().addClass(className.filtered) // 如果uedbet下载结果为空,itemgroup添加filtered的样式
: $item.parent().removeClass(className.filtered) // 如果uedbet下载结果不为空,itemgroup删除filtered样式
;
项目中的html格式如下,具体的显示样式需要单独处理,比如strong标签取消加粗、修改颜色等:
<div class="ui selection dropdown search">
<div class="text">Click to search</div>
<div class="menu">
<div class="itemgroup">
<label>San Francisco</label>
<div class="item">
<span>San Francisco, International Airport</span>
<span>SFO</span>
</div>
<div class="item">
<span>Normal Y. Mineta San Jose International Airport</span>
<span>SJC</span>
</div>
</div>
<div class="itemgroup">
<label>San Francisco</label>
<div class="item">
<span>San Francisco, International Airport</span>
<span>SFO</span>
</div>
<div class="item">
<span>Normal Y. Mineta San Jose International Airport</span>
<span>SJC</span>
</div>
</div>
</div>
</div>
]]>HomeController.cs
public async Task<IActionResult> Index()
{
string path = Request.Path.Value.Trim().ToString();
var r = await _nodeServices.InvokeAsync<string>(@"server.js", path).ConfigureAwait(false);
return Content(r, "text/html");
}
Server.js
const fs = require('fs');
const { createBundleRenderer } = require('vue-server-renderer')
const renderer = createBundleRenderer(require('./vue-ssr-server-bundle.json'), {
runInNewContext: false,
template: fs.readFileSync('./index.html', 'utf-8'),
clientManifest: require('./vue-ssr-client-manifest.json')
})
function renderToString(context) {
//var c = JSON.parse(context.replace(/\\"/g, ""));
//return JSON.stringify(context);
return new Promise((resolve, reject) => {
renderer.renderToString(context, (err, html) => {
resolve(html);
})
})
}
module.exports = async (callback, data) => {
const url = data.replace(/\\"/g, "");
var title = 'Home';
var d = {
title: title,
url: url,
meta: '<meta name="description" content="desc" />'
}
var k = await renderToString(d);
callback(null, k.toString());
}
代码其实很简单,但部署网站的时候还是遇到了一些问题,首先服务器上的.net core版本必须与vs发布所选的版本一致,否则会提示服务器500错误。
我在代码中使用了await,导致页面出现错误的时候不能及时返回,页面会显示超时,callback里面promise返回的结果添加了toString()的方法,是为了避免返回结果可能为 object object 不能由c#解析为string:“_nodeServices.InvokeAsync
有人说这本书:
林特特说:“这世界上只有一种成功,就是以自己喜欢的方式过一生。”
王小波说:“我对自己的要求很低,我活在世上,无非想要明白些道理,遇见些有趣的事。倘能如我所愿,我的一生就算成功。”
杨绛说:“我们曾如此渴望命运的波澜,到最后才发现:人生最曼妙的风景,竟是内心的淡定与从容……我们曾如此期盼外界的认可,到最后才知道:世界是自己的,与他人毫无关系。”
关于本书:
没有写远大的理想,锦绣的前程。
作者把生活里的拧巴、纠结一一融化在淡淡的笔尖。写那些最朴素的人、最朴素的生活。偏偏让你嗅到理想应该有的味道。
合上书,你也许会忽然发现,一直误解了理想的意义,生活不应只是为了周遭的人对自己满意而已。
一点想说的:
这本书是学生时代收到的一份生日礼物。
依稀记得那是一个很忙的阴天,学生会的工作忙的焦头烂额,迎新晚会的贺卡还没做出来,抱着一堆颜料陪学弟学妹排练了一下午,终于把贺卡赶出来了个七七八八。
回宿舍已经快九点了,买了一碗加荷包蛋的清汤面,正在愉快的吸溜,腿腿儿提着个纸袋子进来对我晃了晃说生日快乐宝宝。
于是就有了这本书。
多数时候它用来垫枕头,但是也有偶尔,在繁事绕心头或者在某个坏情绪爆炸的时刻,会在遮光帘里打开小夜灯读一读。
封面提出的核心思想“要有最朴素的生活和最遥远的梦想”,在这个快节奏的浮躁时代应该已经不适用了吧。
只是反复咀嚼,字里行间,不经意会流露一种平淡和满足,仿佛我们在另一个平行世界,都是多金高颜值的超级英雄。
如果说那个时候的我喜欢的是这本书的名字,那么现在的我是由衷喜欢书里面的故事了。
54个人生最温暖的瞬间里,我们渐渐明白,平凡的一生不代表碌碌无为;变得成熟也不意味着要丢掉初心。就算怀揣世上最伟大的梦想,也不妨碍我们得到一个普通人的快乐。
文章来自:2019.02.26 风风(QQ音乐电台-追风少女)
]]>