Asp.net web api 使用Breeze.js连续进行相同的Web API调用时返回的缓存数据

Asp.net web api 使用Breeze.js连续进行相同的Web API调用时返回的缓存数据,asp.net-web-api,breeze,single-page-application,durandal-2.0,Asp.net Web Api,Breeze,Single Page Application,Durandal 2.0,在使用Durandal SPA编写Breeze.js时,我遇到了一个奇怪的问题(主要基于John Papa伟大的SPA Jumpstart()培训),当一个用户尝试连续多次调用同一个服务器API时,服务器只被命中一次,第二次调用时,我似乎得到了缓存数据(调用甚至没有命中服务器),这也可以在Jumpstart示例中复制,下面是在Jumpstart上复制这一点的修改代码 var activate = function () { for (var i = 0 ; i <

在使用Durandal SPA编写Breeze.js时,我遇到了一个奇怪的问题(主要基于John Papa伟大的SPA Jumpstart()培训),当一个用户尝试连续多次调用同一个服务器API时,服务器只被命中一次,第二次调用时,我似乎得到了缓存数据(调用甚至没有命中服务器),这也可以在Jumpstart示例中复制,下面是在Jumpstart上复制这一点的修改代码

 var activate = function () {
            for (var i = 0 ; i < 2 ; i++) {

                 datacontext.getSessionPartials(sessions, true);
            }
        };



var activate = function () {

        for (var i = 0 ; i < 2 ; i++)
        {
            datacontext.getSpeakerPartials(speakers, true);
        }
    };
var activate=函数(){
对于(变量i=0;i<2;i++){
getSessionPartials(sessions,true);
}
};
变量激活=函数(){
对于(变量i=0;i<2;i++)
{
getSpeakerPartials(speakers,true);
}
};
编辑-使用完整代码更新:

我的Viewmodel的代码

define(['services/datacontext'], function (datacontext) {
    var speakers = ko.observableArray();

    var activate = function () {

        for (var i = 0 ; i < 2 ; i++)
        {
            datacontext.getSpeakerPartials(speakers, true);
        }
    };
    var refresh = function () {
        return datacontext.getSpeakerPartials(speakers, true);
    };

    var vm = {
        activate: activate,
        speakers: speakers,
        title: 'Speakers',
        refresh: refresh
    };

    return vm;
});
define(['services/datacontext'],函数(datacontext){
变量演讲者=ko.observearray();
变量激活=函数(){
对于(变量i=0;i<2;i++)
{
getSpeakerPartials(speakers,true);
}
};
var refresh=函数(){
返回datacontext.getSpeakerPartials(speakers,true);
};
var vm={
激活:激活,
发言者:发言者,
标题:"演讲者",,
刷新:刷新
};
返回虚拟机;
});
下面是我的datacontext/服务的代码:

define([
    'durandal/system',
    'services/model',
    'config',
    'services/logger',
    'services/breeze.partial-entities'],
    function (system, model, config, logger, partialMapper) {
        var EntityQuery = breeze.EntityQuery;
        var manager = configureBreezeManager();
        var orderBy = model.orderBy;
        var entityNames = model.entityNames;

        var getSpeakerPartials = function (speakersObservable, forceRemote) {

            if (!forceRemote) {                
                var p = getLocal('Persons', orderBy.speaker);
                if (p.length > 0) {
                    speakersObservable(p);
                    return Q.resolve();
                }
            }

            var query = EntityQuery.from('Speakers')
                .select('id, firstName, lastName, imageSource')
                .orderBy(orderBy.speaker);

            return manager.executeQuery(query)
                .then(querySucceeded)
                .fail(queryFailed);

            function querySucceeded(data) {
                var list = partialMapper.mapDtosToEntities(
                    manager, data.results, entityNames.speaker, 'id');
                if (speakersObservable) {
                    speakersObservable(list);
                }
                log('Retrieved [Speaker] from remote data source',
                    data, true);
            }
        };

        var getSessionPartials = function (sessionsObservable, forceRemote) {
            if (!forceRemote) {
                var s = getLocal('Sessions', orderBy.session);
                if (s.length > 3) {
                    // Edge case
                    // We need this check because we may have 1 entity already.
                    // If we start on a specific person, this may happen. So we check for > 2, really
                    sessionsObservable(s);
                    return Q.resolve();
                }
            }

            var query = EntityQuery.from('Sessions')
                .select('id, title, code, speakerId, trackId, timeSlotId, roomId, level, tags')
                .orderBy('timeSlotId, level, speaker.firstName');

            return manager.executeQuery(query)
                .then(querySucceeded)
                .fail(queryFailed);

            function querySucceeded(data) {
                var list = partialMapper.mapDtosToEntities(
                    manager, data.results, entityNames.session, 'id');
                if (sessionsObservable) {
                    sessionsObservable(list);
                }
                log('Retrieved [Sessions] from remote data source',
                    data, true);
            }
        };

        var getSessionById = function(sessionId, sessionObservable) {
            // 1st - fetchEntityByKey will look in local cache 
            // first (because 3rd parm is true) 
            // if not there then it will go remote
            return manager.fetchEntityByKey(
                entityNames.session, sessionId, true)
                .then(fetchSucceeded)
                .fail(queryFailed);

            // 2nd - Refresh the entity from remote store (if needed)
            function fetchSucceeded(data) {
                var s = data.entity;
                return s.isPartial() ? refreshSession(s) : sessionObservable(s);
            }

            function refreshSession(session) {
                return EntityQuery.fromEntities(session)
                    .using(manager).execute()
                    .then(querySucceeded)
                    .fail(queryFailed);
            }

            function querySucceeded(data) {
                var s = data.results[0];
                s.isPartial(false);
                log('Retrieved [Session] from remote data source', s, true);
                return sessionObservable(s);
            }

        };

        var cancelChanges = function() {
            manager.rejectChanges();
            log('Canceled changes', null, true);
        };

        var saveChanges = function() {
            return manager.saveChanges()
                .then(saveSucceeded)
                .fail(saveFailed);

            function saveSucceeded(saveResult) {
                log('Saved data successfully', saveResult, true);
            }

            function saveFailed(error) {
                var msg = 'Save failed: ' + getErrorMessages(error);
                logError(msg, error);
                error.message = msg;
                throw error;
            }
        };

        var primeData = function () {
            var promise = Q.all([
                getLookups(),
                getSpeakerPartials(null, true)])
                .then(applyValidators);

            return promise.then(success);

            function success() {
                datacontext.lookups = {
                    rooms: getLocal('Rooms', 'name', true),
                    tracks: getLocal('Tracks', 'name', true),
                    timeslots: getLocal('TimeSlots', 'start', true),
                    speakers: getLocal('Persons', orderBy.speaker, true)
                };
                log('Primed data', datacontext.lookups);
            }

            function applyValidators() {
                model.applySessionValidators(manager.metadataStore);
            }

        };

        var createSession = function() {
            return manager.createEntity(entityNames.session);
        };

        var hasChanges = ko.observable(false);

        manager.hasChangesChanged.subscribe(function(eventArgs) {
            hasChanges(eventArgs.hasChanges);
        });

        var datacontext = {
            createSession: createSession,
            getSessionPartials: getSessionPartials,
            getSpeakerPartials: getSpeakerPartials,
            hasChanges: hasChanges,
            getSessionById: getSessionById,
            primeData: primeData,
            cancelChanges: cancelChanges,
            saveChanges: saveChanges
        };

        return datacontext;

        //#region Internal methods        

        function getLocal(resource, ordering, includeNullos) {
            var query = EntityQuery.from(resource)
                .orderBy(ordering);
            if (!includeNullos) {
                query = query.where('id', '!=', 0);
            }
            return manager.executeQueryLocally(query);
        }

        function getErrorMessages(error) {
            var msg = error.message;
            if (msg.match(/validation error/i)) {
                return getValidationMessages(error);
            }
            return msg;
        }

        function getValidationMessages(error) {
            try {
                //foreach entity with a validation error
                return error.entitiesWithErrors.map(function(entity) {
                    // get each validation error
                    return entity.entityAspect.getValidationErrors().map(function(valError) {
                        // return the error message from the validation
                        return valError.errorMessage;
                    }).join('; <br/>');
                }).join('; <br/>');
            }
            catch (e) { }
            return 'validation error';
        }

        function queryFailed(error) {
            var msg = 'Error retreiving data. ' + error.message;
            logError(msg, error);
            throw error;
        }

        function configureBreezeManager() {
            breeze.NamingConvention.camelCase.setAsDefault();
            var mgr = new breeze.EntityManager(config.remoteServiceName);
            model.configureMetadataStore(mgr.metadataStore);
            return mgr;
        }

        function getLookups() {
            return EntityQuery.from('Lookups')
                .using(manager).execute()
                .then(processLookups)
                .fail(queryFailed);
        }

        function processLookups() {
            model.createNullos(manager);
        }


        function log(msg, data, showToast) {
            logger.log(msg, data, system.getModuleId(datacontext), showToast);
        }

        function logError(msg, error) {
            logger.logError(msg, error, system.getModuleId(datacontext), true);
        }
        //#endregion
});
定义([
“durandal/系统”,
“服务/模型”,
“配置”,
“服务/记录器”,
“服务/breeze.partial实体”],
功能(系统、型号、配置、记录器、partialMapper){
var EntityQuery=breeze.EntityQuery;
var manager=configureBreezeManager();
var orderBy=model.orderBy;
var entityNames=model.entityNames;
var getSpeakerPartials=函数(speakersObservable,forceRemote){
如果(!forceRemote){
var p=getLocal('Persons',orderBy.speaker);
如果(p.length>0){
可观察的说话人(p);
返回Q.resolve();
}
}
var query=EntityQuery.from('Speakers')
.select('id,firstName,lastName,imageSource')
.orderBy(orderBy.speaker);
return manager.executeQuery(查询)
.然后(查询成功)
。失败(查询失败);
函数查询成功(数据){
var list=partialMapper.MapdToToEntities(
经理,data.results,entityNames.speaker,“id”);
if(可观察到的扬声器){
可观察的说话者(列表);
}
日志('从远程数据源检索到[扬声器],
数据(真实);
}
};
var getSessionPartials=函数(sessionsObservable,forceRemote){
如果(!forceRemote){
var s=getLocal('Sessions',orderBy.session);
如果(s.长度>3){
//边缘案例
//我们需要这张支票,因为我们可能已经有1个实体了。
//如果我们从一个特定的人开始,这可能会发生。所以我们检查>2,真的
可观察的会期;
返回Q.resolve();
}
}
var query=EntityQuery.from('会话')
.select('id、title、code、speakerId、trackId、timeSlotId、roomId、level、tags')
.orderBy('timeSlotId,level,speaker.firstName');
return manager.executeQuery(查询)
.然后(查询成功)
。失败(查询失败);
函数查询成功(数据){
var list=partialMapper.MapdToToEntities(
manager、data.results、entityNames.session、“id”);
if(可观察的会话){
可观察的会话(列表);
}
日志('从远程数据源检索[会话],
数据(真实);
}
};
var getSessionById=函数(sessionId,sessionObservable){
//第一个-fetchEntityByKey将在本地缓存中查找
//第一(因为第三个参数是正确的)
//如果不在那里,那么它将远程运行
return manager.fetchEntityByKey(
entityNames.session,sessionId,true)
.然后(成功)
。失败(查询失败);
//第二个-从远程存储刷新实体(如果需要)
函数获取成功(数据){
var s=数据实体;
返回s.isPartial()?刷新会话:会话可观察;
}
功能刷新会话(会话){
返回EntityQuery.fromEntities(会话)
.using(manager.execute())
.然后(查询成功)
。失败(查询失败);
}
函数查询成功(数据){
var s=数据。结果[0];
s、 i部分(假);
日志('从远程数据源检索[Session],s,true);
可观测的返回会话;
}
};
var cancelChanges=函数(){
manager.rejectChanges();
日志(“已取消的更改”,null,true);
};
var saveChanges=function(){
returnmanager.saveChanges()
.然后(保存成功)
.失败(保存失败);
函数savesuccessed(saveResult){
日志(“成功保存数据”,保存结果,true);
}
函数保存失败(错误){
var msg='保存失败:'+getErrorMessages(错误);
日志错误(消息,错误);
error.message=msg;
投掷误差;
}
namespace CodeCamper.Controllers
{
    [BreezeController]
    public class BreezeController : ApiController
    {
        readonly EFContextProvider<CodeCamperDbContext>  _contextProvider =
            new EFContextProvider<CodeCamperDbContext>();

        [HttpGet]
        public string Metadata()
        {
            return _contextProvider.Metadata();
        }

        [HttpPost]
        public SaveResult SaveChanges(JObject saveBundle)
        {
            return _contextProvider.SaveChanges(saveBundle);
        }

        [HttpGet]
        public object Lookups()
        {
            var rooms =  _contextProvider.Context.Rooms;
            var tracks =  _contextProvider.Context.Tracks;
            var timeslots =  _contextProvider.Context.TimeSlots;
            return new {rooms, tracks, timeslots};
        }

        [HttpGet]
        public IQueryable<Session> Sessions()
        {
            return _contextProvider.Context.Sessions;
        }

        [HttpGet]
        public IQueryable<Person> Persons()
        {
            return _contextProvider.Context.Persons;
        }

        [HttpGet]
        public IQueryable<Person> Speakers()
        {
            return _contextProvider.Context.Persons
                .Where(p => p.SpeakerSessions.Any());
        }

   }
}