/// <summary> /// Marks a imaging as completed. /// </summary> void IImagingTaskProvider.ImagedPlate(Formulatrix.Integrations.ImagerLink.IRobot robot, string plateID, string imagingID) { // Check arguments - do it up front to avoid possible inconsistencies later if (null == robot) { throw new System.NullReferenceException("robot must not be null"); } if (null == plateID) { throw new System.NullReferenceException("plateID must not be null"); } if (null == imagingID) { throw new System.NullReferenceException("imagingID must not be null"); } // Log the call to the method if (_log.IsDebugEnabled) { string msg = "Called " + this + ".ImagedPlate(robot=" + RobotUtils.iRobotToString(robot) + ", plateID=\"" + plateID + "\", imagingID=\"" + imagingID + "\")"; _log.Debug(msg); } // Set the request imagedPlate request = new imagedPlate(); request.robot = OPPF.Utilities.Robot2Utils.createProxy(robot); request.plateID = plateID; request.imagingID = imagingID; // Make the call WSPlate wsPlate = WSPlateFactory.getWSPlate2(); imagedPlateResponse response = null; try { response = wsPlate.imagedPlate(request); } catch (Exception e) { // Log it string msg = "WSPlate.imagedPlate threw " + e.GetType() + ": " + e.Message + " - panic!"; msg = msg + "\nin " + this + ".ImagedPlate(robot=" + RobotUtils.iRobotToString(robot) + ", plateID=\"" + plateID + "\", imagingID=\"" + imagingID + "\")"; if (e is System.Web.Services.Protocols.SoapException) { System.Web.Services.Protocols.SoapException ee = (System.Web.Services.Protocols.SoapException)e; msg = msg + "\n\n" + ee.Detail.InnerXml; } _log.Fatal(msg, e); // Panic throw e; } // Webservice always returns true if it doesn't throw an exception return; }
/// <summary> /// If this <c>IImagingTaskProvider</c> supports changing priority, /// changes the priority of the IImagingTask with this <c>dateToImage</c>. /// </summary> void IImagingTaskProvider.UpdatedPriority(Formulatrix.Integrations.ImagerLink.IRobot robot, string plateID, DateTime dateToImage, int priority) { // Check arguments - do it up front to avoid possible inconsistencies later if (null == robot) { throw new System.NullReferenceException("robot must not be null"); } if (null == plateID) { throw new System.NullReferenceException("plateID must not be null"); } // Log the call to the method if (_log.IsDebugEnabled) { string msg = "Called " + this + ".UpdatedPriority(robot=" + RobotUtils.iRobotToString(robot) + ", plateID=\"" + plateID + "\", dateToImage=" + dateToImage.ToUniversalTime().ToString() + " UTC, priority=" + priority + ")"; _log.Debug(msg); } // Set the request updatedPriority request = new updatedPriority(); request.robot = OPPF.Utilities.Robot2Utils.createProxy(robot); request.plateID = plateID; // .NET < 2.0 //request.dateToImage = dateToImage; // .NET >= 2.0 request.dateToImage = dateToImage.ToUniversalTime(); request.priority = priority; // Make the call WSPlate wsPlate = WSPlateFactory.getWSPlate2(); try { wsPlate.updatedPriority(request); } catch (Exception e) { // Log it string msg = "WSPlate.updatedPriority threw " + e.GetType() + ": " + e.Message + " - ignoring"; if (e is System.Web.Services.Protocols.SoapException) { System.Web.Services.Protocols.SoapException ee = (System.Web.Services.Protocols.SoapException)e; msg = msg + "\n\n" + ee.Detail.InnerXml; } _log.Warn(msg, e); // Don't rethrow - just return - don't really care if this didn't work return; } // Webservice always returns true if there is no exception return; }
/// <summary> /// Return <c>true</c> if this provider supplies <c>IImagingTask.Priority</c>. /// Otherwise the imager should manage individual task priority. /// </summary> bool IImagingTaskProvider.SupportsPriority(Formulatrix.Integrations.ImagerLink.IRobot robot) { // OPPF PERFORMANCE BODGE - Actually this method should always return true! return(true); // Check arguments - do it up front to avoid possible inconsistencies later if (null == robot) { throw new System.NullReferenceException("robot must not be null"); } // Log the call to the method if (_log.IsDebugEnabled) { string msg = "Called " + this + ".SupportsPriority(robot=" + RobotUtils.iRobotToString(robot) + ")"; _log.Debug(msg); } // Set the request supportsPriority request = new supportsPriority(); request.robot = OPPF.Utilities.Robot2Utils.createProxy(robot); // Make the call WSPlate wsPlate = WSPlateFactory.getWSPlate2(); supportsPriorityResponse response = null; try { response = wsPlate.supportsPriority(request); } catch (Exception e) { // Log it string msg = "WSPlate.supportsPriority threw " + e.GetType() + ": " + e.Message + " - ignoring"; if (e is System.Web.Services.Protocols.SoapException) { System.Web.Services.Protocols.SoapException ee = (System.Web.Services.Protocols.SoapException)e; msg = msg + "\n\n" + ee.Detail.InnerXml; } _log.Warn(msg, e); // Don't rethrow - just return false return(false); } // Return the response's value //_log.Debug("supportsPriority returned " + response.supportsPriorityReturn); return(response.supportsPriorityReturn); }
/// <summary> /// Marks an imaging as skipped. /// </summary> public void SkippedImaging(Formulatrix.Integrations.ImagerLink.IRobot robot, string plateID, DateTime dateToImage) { // Check arguments - do it up front to avoid possible inconsistencies later if (null == robot) { throw new System.NullReferenceException("robot must not be null"); } if (null == plateID) { throw new System.NullReferenceException("plateID must not be null"); } // Log the call to the method if (_log.IsDebugEnabled) { string msg = "Called " + this + ".SkippedImaging(robot=" + RobotUtils.iRobotToString(robot) + ", plateID=\"" + plateID + "\", dateToImage=" + dateToImage.ToUniversalTime().ToString() + " UTC)"; _log.Debug(msg); } // Set the request skippedImaging request = new skippedImaging(); request.robot = global::OPPF.Utilities.Robot2Utils.createProxy(robot); request.plateID = plateID; request.dateToImage = dateToImage.ToUniversalTime(); // Make the call WSPlate wsPlate = WSPlateFactory.getWSPlate2(); skippedImagingResponse response = null; try { response = wsPlate.skippedImaging(request); } catch (Exception e) { // Log it string msg = "WSPlate.skippedImaging threw " + e.GetType() + ": " + e.Message + " - ignoring"; msg = msg + "\nin " + this + ".SkippedImaging(robot=" + RobotUtils.iRobotToString(robot) + ", plateID=\"" + plateID + "\", dateToImage=" + dateToImage.ToUniversalTime().ToString() + " UTC)"; msg = msg + WSPlateFactory.SoapExceptionToString(e); _log.Warn(msg, e); // Don't rethrow - just return - don't really care if this didn't work return; } // Webservice always returns true if it doesn't throw an exception return; }
/// <summary> /// Plate is starting to image. Returns an imaging identifier that will be /// embedded in the image names, and returned in ImagedPlate or null if /// the ImagingID is unavailable. /// </summary> public string ImagingPlate(Formulatrix.Integrations.ImagerLink.IRobot robot, string plateID, bool scheduled, DateTime dateToImage, DateTime dateImaged) { // Check arguments - do it up front to avoid possible inconsistencies later if (null == robot) { throw new System.NullReferenceException("robot must not be null"); } if (null == plateID) { throw new System.NullReferenceException("plateID must not be null"); } // Log the call to the method if (_log.IsInfoEnabled) { string msg = "Called " + this + ".ImagingPlate(robot=" + RobotUtils.iRobotToString(robot) + ", plateID=\"" + plateID + "\", scheduled=\"" + scheduled + "\", dateToImage=" + dateToImage.ToUniversalTime().ToString() + " UTC, dateImaged=" + dateImaged.ToUniversalTime().ToString() + " UTC)"; _log.Info(msg); } // Set the request imagingPlate request = new imagingPlate(); request.robot = global::OPPF.Utilities.Robot2Utils.createProxy(robot); request.plateID = plateID; request.scheduled = scheduled; //request.dateToImage = dateToImage.ToUniversalTime(); // Is this a fix for the date collision problem? if (scheduled) { request.dateToImage = dateToImage.ToUniversalTime(); } else { request.dateToImage = dateImaged.ToUniversalTime(); } request.dateImaged = dateImaged.ToUniversalTime(); // Make the call WSPlate wsPlate = WSPlateFactory.getWSPlate2(); imagingPlateResponse response = null; try { response = wsPlate.imagingPlate(request); } catch (Exception e) { string msg = "WSPlate.imagingPlate threw " + e.GetType() + ": " + e.Message + " - panic!"; msg = msg + "\nin " + this + ".ImagingPlate(robot=" + RobotUtils.iRobotToString(robot) + ", plateID=\"" + plateID + "\", dateToImage=" + dateToImage.ToUniversalTime().ToString() + " UTC, dateImaged=" + dateImaged.ToUniversalTime().ToString() + " UTC)"; msg = msg + WSPlateFactory.SoapExceptionToString(e); _log.Fatal(msg, e); // Panic throw; } // If we got no response if (null == response) { string msg = "WSPlate.imagingPlate returned null - panic!"; msg = msg + "\nin " + this + ".ImagingPlate(robot=" + RobotUtils.iRobotToString(robot) + ", plateID=\"" + plateID + "\", dateToImage=" + dateToImage.ToUniversalTime().ToString() + " UTC, dateImaged=" + dateImaged.ToUniversalTime().ToString() + " UTC)"; _log.Fatal(msg); // Panic throw new System.NullReferenceException(msg); } // If we got a null imagingID if (null == response.imagingPlateReturn) { string msg = "WSPlate.imagingPlate returned a null imagingID - panic!"; msg = msg + "\nin " + this + ".ImagingPlate(robot=" + RobotUtils.iRobotToString(robot) + ", plateID=\"" + plateID + "\", dateToImage=" + dateToImage.ToUniversalTime().ToString() + " UTC, dateImaged=" + dateImaged.ToUniversalTime().ToString() + " UTC)"; _log.Fatal(msg); // Panic throw new System.NullReferenceException(msg); } // Return the imagingID return(response.imagingPlateReturn); }
/// <summary> /// Web service version of GetImagingTasks - useful because it will /// cause a full schedule to be written if one doesn't already /// exist. /// /// Warning - this is a lot slower than going straight to platedb! /// </summary> /// <param name="robot">The robot</param> /// <param name="plateID">The barcode of the plate</param> /// <returns></returns> public IImagingTask[] GetImagingTasksFromWebService(Formulatrix.Integrations.ImagerLink.IRobot robot, string plateID) { // Check arguments - do it up front to avoid possible inconsistencies later if (null == robot) { throw new System.NullReferenceException("robot must not be null"); } if (null == plateID) { throw new System.NullReferenceException("plateID must not be null"); } // Log the call if (_log.IsInfoEnabled) { string msg = "Calling WSPlate.getImagingTasks() for plate " + plateID + ", robot " + RobotUtils.iRobotToString(robot); _log.Info(msg); } // Declare the array that will be populated and returned // - default to a zero-length array IImagingTask[] iImagingTasks = new IImagingTask[0]; // Set the request getImagingTasks request = new getImagingTasks(); request.robot = global::OPPF.Utilities.Robot2Utils.createProxy(robot); request.plateID = plateID; // Make the call getImagingTasksResponse response = null; try { WSPlate wsPlate = WSPlateFactory.getWSPlate2(); wsPlate.Timeout = 10000; response = wsPlate.getImagingTasks(request); } catch (Exception e) { // Log it string msg = "WSPlate.getImagingTasks threw " + e.GetType() + ": " + e.Message + " for plateid \"" + plateID + "\" in robot \"" + robot.Name + "\" - returning empty IImagingTask[]"; msg = msg + WSPlateFactory.SoapExceptionToString(e); _log.Error(msg, e); // Don't rethrow - just return empty array return(iImagingTasks); } // If we got a response if (null != response) { // Get the array of ImagingTasks from the response global::OPPF.Proxies2.ImagingTask[] wrapper = response.wrapper; // Convert to IImagingTasks iImagingTasks = new IImagingTask[wrapper.GetLength(0)]; for (int i = 0; i < wrapper.GetLength(0); i++) { global::OPPF.Integrations.ImagerLink.Scheduling.ImagingTask task = new global::OPPF.Integrations.ImagerLink.Scheduling.ImagingTask(); if (wrapper[i].dateImaged.HasValue) { task.SetDateImaged(wrapper[i].dateImaged.Value); } task.SetDateToImage(wrapper[i].dateToImage); task.SetInQueue(wrapper[i].inQueue); task.SetPriority(wrapper[i].priority); task.SetState((Formulatrix.Integrations.ImagerLink.Scheduling.ImagingState)wrapper[i].state); iImagingTasks[i] = task; } } // Return the IImagingTask array return(iImagingTasks); }
/// <summary> /// Retrieves a plate description from the web service. /// </summary> /// <param name="robot">The robot to find the plate type for.</param> /// <param name="plateID">The <c>plateID</c> of the plate.</param> /// <returns>The <c>IPlateInfo</c> describing the plate.</returns> public IPlateInfo FetchPlateInfo(IRobot robot, string plateID) { // Check arguments - do it up front to avoid possible inconsistencies later if (robot == null) { throw new System.NullReferenceException("robot must not be null"); } if (plateID == null) { throw new System.NullReferenceException("plateID must not be null"); } // Log the call if (_log.IsDebugEnabled) { string msg = "Called " + this + ".FetchPlateInfo(robot=" + robot.ToString() + ", plateID=\"" + plateID + "\")"; _log.Debug(msg); } // Special case for ReliabilityTestPlate if ("ReliabilityTestPlate".Equals(plateID)) { OPPF.Integrations.ImagerLink.PlateInfo dummy = new OPPF.Integrations.ImagerLink.PlateInfo(); dummy.SetDateDispensed(DateTime.Now); dummy.SetExperimentName("Dummy Expt Name"); dummy.SetPlateNumber(1); dummy.SetPlateTypeID("1"); dummy.SetProjectName("Dummy Project Name"); dummy.SetUserEmail("DummyEmailAddress"); dummy.SetUserName("Dummy UserName"); return(dummy); } // Declare the return variable OPPF.Integrations.ImagerLink.PlateInfo pi = null; try { // Create and populate the request object getPlateInfo request = new getPlateInfo(); request.robot = OPPF.Utilities.Robot2Utils.createProxy(robot); request.plateID = plateID; // Make the web service call WSPlate wsPlate = WSPlateFactory.getWSPlate2(); _log.Info("Calling WSPlate.getPlateInfo()"); getPlateInfoResponse response = wsPlate.getPlateInfo(request); // Get the webservice proxy PlateInfo OPPF.Proxies2.PlateInfo ppi = response.getPlateInfoReturn; // Map it into an IPlateInfo pi = new OPPF.Integrations.ImagerLink.PlateInfo(); pi.SetDateDispensed(ppi.dateDispensed); pi.SetExperimentName(ppi.experimentName); pi.SetPlateNumber(ppi.plateNumber); // TODO Figure out how to get pims to tell us the right answer //pi.SetPlateTypeID(ppi.plateTypeID); pi.SetPlateTypeID(PlateInfoProviderNew.getIDForName(ppi.plateTypeID)); pi.SetProjectName(ppi.projectName); pi.SetUserEmail(ppi.userEmail); pi.SetUserName(ppi.userName); } catch (Exception e) { string msg = "WSPlate.getPlateInfo threw " + e.GetType() + ":\n" + e.Message + "\nfor plate \"" + plateID + "\" in robot \"" + robot.Name + "\"\n - probably not in LIMS - not fatal."; if (e is System.Web.Services.Protocols.SoapException) { System.Web.Services.Protocols.SoapException ee = (System.Web.Services.Protocols.SoapException)e; msg = msg + "\n\n" + ee.Detail.InnerXml; } // Log it _log.Error(msg, e); // Don't rethrow - return null - don't want to stop imaging } // Return the IPlateInfo return(pi); }
/// <summary> /// Plate is starting to image. Returns an imaging identifier that will be /// embedded in the image names, and returned in ImagedPlate or null if /// the ImagingID is unavailable. /// </summary> string IImagingTaskProvider.ImagingPlate(Formulatrix.Integrations.ImagerLink.IRobot robot, string plateID, bool scheduled, DateTime dateToImage, DateTime dateImaged) { // Check arguments - do it up front to avoid possible inconsistencies later if (null == robot) { throw new System.NullReferenceException("robot must not be null"); } if (null == plateID) { throw new System.NullReferenceException("plateID must not be null"); } // Log the call to the method if (_log.IsDebugEnabled) { string msg = "Called " + this + ".ImagingPlate(robot=" + RobotUtils.iRobotToString(robot) + ", plateID=\"" + plateID + "\", dateToImage=" + dateToImage.ToUniversalTime().ToString() + " UTC, dateImaged=" + dateImaged.ToUniversalTime().ToString() + " UTC)"; _log.Debug(msg); } // Set the request imagingPlate request = new imagingPlate(); request.robot = OPPF.Utilities.Robot2Utils.createProxy(robot); request.plateID = plateID; request.scheduled = scheduled; request.dateToImage = dateToImage.ToUniversalTime(); request.dateImaged = dateImaged.ToUniversalTime(); // Make the call WSPlate wsPlate = WSPlateFactory.getWSPlate2(); imagingPlateResponse response = null; try { response = wsPlate.imagingPlate(request); } catch (Exception e) { string msg = "WSPlate.imagingPlate threw " + e.GetType() + ": " + e.Message + " - panic!"; msg = msg + "\nin " + this + ".ImagingPlate(robot=" + RobotUtils.iRobotToString(robot) + ", plateID=\"" + plateID + "\", dateToImage=" + dateToImage.ToUniversalTime().ToString() + " UTC, dateImaged=" + dateImaged.ToUniversalTime().ToString() + " UTC)"; if (e is System.Web.Services.Protocols.SoapException) { System.Web.Services.Protocols.SoapException ee = (System.Web.Services.Protocols.SoapException)e; msg = msg + "\n\n" + ee.Detail.InnerXml; } _log.Fatal(msg, e); // Panic throw e; } // If we got no response if (null == response) { string msg = "WSPlate.imagingPlate returned null - panic!"; msg = msg + "\nin " + this + ".ImagingPlate(robot=" + RobotUtils.iRobotToString(robot) + ", plateID=\"" + plateID + "\", dateToImage=" + dateToImage.ToUniversalTime().ToString() + " UTC, dateImaged=" + dateImaged.ToUniversalTime().ToString() + " UTC)"; _log.Fatal(msg); // Panic throw new System.NullReferenceException(msg); } // If we got a null imagingID if (null == response.imagingPlateReturn) { string msg = "WSPlate.imagingPlate returned a null imagingID - panic!"; msg = msg + "\nin " + this + ".ImagingPlate(robot=" + RobotUtils.iRobotToString(robot) + ", plateID=\"" + plateID + "\", dateToImage=" + dateToImage.ToUniversalTime().ToString() + " UTC, dateImaged=" + dateImaged.ToUniversalTime().ToString() + " UTC)"; _log.Fatal(msg); // Panic throw new System.NullReferenceException(msg); } // Return the imagingID return(response.imagingPlateReturn); }
/// <summary> /// Find and process the ImageInfo xml files /// </summary> /// <returns>True if there may be more files to process.</returns> public bool processImageInfos() { bool moreImageInfos = false; DirectoryInfo di = new DirectoryInfo(imageInfosDir); DirectoryInfo processed = new DirectoryInfo(Path.Combine(di.FullName, @"Processed")); if (!processed.Exists) { processed.Create(); } DirectoryInfo quarantine = new DirectoryInfo(Path.Combine(di.FullName, @"Quarantine")); if (!quarantine.Exists) { quarantine.Create(); } // TODO Potentially expensive - can we iterate? FileInfo[] files = di.GetFiles("*.xml", SearchOption.TopDirectoryOnly); List <UploadImage> uploadImageList = new List <UploadImage>(); //List<FileInfo> filesToProcess = new List<FileInfo>(); Dictionary <string, FileInfo> urlToFiles = new Dictionary <string, FileInfo>(); long threshold = DateTime.Now.Ticks - (TimeSpan.TicksPerSecond * 10); try { foreach (FileInfo fi in files) { // File at least 10 seconds old if ((threshold > fi.CreationTimeUtc.Ticks) && (threshold > fi.LastWriteTimeUtc.Ticks)) { // Read XML XmlSerializer serializer = new XmlSerializer(typeof(ImageInfo)); TextReader reader = new StreamReader(fi.FullName); ImageInfo imageInfo = (ImageInfo)serializer.Deserialize(reader); reader.Close(); OPPF.Proxies2.UploadImage uploadImage = parseImageInfo(imageInfo); uploadImageList.Add(uploadImage); //filesToProcess.Add(fi); urlToFiles.Add(uploadImage.url, fi); if (maxChunk <= uploadImageList.Count) { moreImageInfos = true; break; } } } if (0 < uploadImageList.Count) { OPPF.Proxies2.uploadImages uploadImagesElement = new uploadImages(); uploadImagesElement.wrapper = uploadImageList.ToArray(); WSPlate ws = WSPlateFactory.getWSPlate2(); OPPF.Proxies2.uploadImagesResponse response = ws.uploadImages(uploadImagesElement); OPPF.Proxies2.UploadImageResponse[] responses = response.wrapper; /* * foreach (FileInfo src in filesToProcess) * { * string dest = Path.Combine(processed.FullName, src.Name); * src.MoveTo(dest); * log.Info("Processed " + src.FullName); * } */ for (int i = 0; i < responses.Length; i++) { FileInfo src; urlToFiles.TryGetValue(responses[i].url, out src); if (null == src) { log.Error("Failed to match url " + responses[i].url + " to known image file"); } else if (responses[i].ok) { string dest = Path.Combine(processed.FullName, src.Name); src.MoveTo(dest); log.Info("Processed " + src.FullName); } else { string dest = Path.Combine(quarantine.FullName, src.Name); src.MoveTo(dest); log.Warn("Quarantined " + src.FullName + ": " + responses[i].reason); } } } else { log.Info("Nothing to do"); } } catch (Exception e) { // Log it log.Error(e); Dictionary <string, FileInfo> .ValueCollection filesToProcess = urlToFiles.Values; foreach (FileInfo src in filesToProcess) { try { string dest = Path.Combine(quarantine.FullName, src.Name); src.MoveTo(dest); log.Warn("Quarantined " + src.FullName + ": " + e.Message, e); } catch (Exception e2) { // Log it log.Error("Failed to Quarantine " + src.FullName + ": " + e2.Message, e2); } } } return(moreImageInfos); }
/// <summary> /// Retrieve all the plate types. The list of PlateTypes is cached for _cacheLifetime min. /// </summary> /// <param name="robot">The robot to find the plate types for.</param> /// <returns>An array of plate types, or null if there are none.</returns> public IPlateType[] GetPlateTypes(IRobot robot) { // Check arguments - do it up front to avoid possible inconsistencies later if (robot == null) { throw new System.NullReferenceException("robot must not be null"); } // Log the call if (_log.IsDebugEnabled) { string msg = "Called " + this + ".GetPlateTypes(robot=" + robot.ToString() + ")"; _log.Debug(msg); } // Return cached values if appropriate if ((_plateTypes != null) && (System.DateTime.Now.Ticks <= _plateTypesCacheExpires)) { _log.Debug("GetPlateTypes() using cached response"); return(_plateTypes); } _log.Debug("GetPlateTypes() refreshing cache"); // Sychronize this block as we are interacting with the cache lock (_plateTypesLock) { try { // Create and populate the request object getPlateTypes request = new getPlateTypes(); request.robot = global::OPPF.Utilities.RobotUtils.createProxy(robot); // Make the web service call WSPlate wsPlate = new WSPlate(); // New stuff wsPlate.Url = "http://localhost:8080/xtalpims-ws/services/WSPlate.WSPlateSOAP12port_http/"; ServicePointManager.Expect100Continue = false; wsPlate.Credentials = new NetworkCredential("jon", "test123"); // End new stuff getPlateTypesResponse response = wsPlate.getPlateTypes(request); // Get the array of proxy PlateType[] global::OPPF.Proxies.PlateType[] pptArray = response.wrapper; // Map into an array of IPlateType[] global::OPPF.Integrations.ImagerLink.PlateType[] iptArray = new global::OPPF.Integrations.ImagerLink.PlateType[pptArray.Length]; int i = 0; foreach (global::OPPF.Proxies.PlateType ppt in pptArray) { iptArray[i] = new global::OPPF.Integrations.ImagerLink.PlateType(); iptArray[i].SetID(ppt.iD); iptArray[i].SetName(ppt.name); iptArray[i].SetNumColumns(ppt.numColumns); iptArray[i].SetNumDrops(ppt.numDrops); iptArray[i].SetNumRows(ppt.numRows); i++; } // Copy into the cache and update cache expiry _plateTypes = iptArray; _plateTypesCacheExpires = System.DateTime.Now.Ticks + _cacheLifetime; _log.Debug("GetPlateTypes() using fresh response"); } catch (Exception e) { // Log it string msg = "WSPlate.getPlateTypes threw " + e.GetType() + ": " + e.Message + " for robot \"" + robot.Name + "\" - returning null"; msg = msg + WSPlateFactory.SoapExceptionToString(e); _log.Error(msg, e); // Don't rethrow - return cache (which might be null) - don't want to stop imaging } } // Return the array of IPlateType[] return(_plateTypes); }