/// <summary> /// Build the HTTP content for the request based on the parameters /// </summary> /// <returns>The request.</returns> public HttpContent BuildRequest(BlastRequestParameters blastParams) { if (string.IsNullOrWhiteSpace(blastParams.Database)) { throw new ArgumentException("Database must be supplied."); } if (string.IsNullOrWhiteSpace(blastParams.Program)) { throw new ArgumentException("Program must be supplied."); } if (blastParams.Sequences.Count == 0) { throw new ArgumentException("Must have at least one sequence."); } // Check that all sequences are same alphabet if (blastParams.Sequences.Count > 1) { ISequence primary = blastParams.Sequences[0]; for (int i = 1; i < blastParams.Sequences.Count; i++) { if (!Alphabets.CheckIsFromSameBase(primary.Alphabet, blastParams.Sequences[i].Alphabet)) { throw new ArgumentException("Sequences must all share the same base alphabet."); } } } var data = new List <KeyValuePair <string, string> > { this.CreateKVP("CMD", "Put") }; if (blastParams.Program == BlastProgram.Megablast) { data.Add(this.CreateKVP("PROGRAM", BlastProgram.Blastn)); data.Add(this.CreateKVP("MEGABLAST", "ON")); } else { data.Add(this.CreateKVP("PROGRAM", blastParams.Program)); } data.Add(this.CreateKVP("DATABASE", blastParams.Database)); data.AddRange(blastParams.ExtraParameters); // Add the sequences. StringBuilder sb = new StringBuilder(); foreach (var seq in blastParams.Sequences) { sb.Append(seq.ConvertToString()); } data.Add(this.CreateKVP("QUERY", sb.ToString())); return(new FormUrlEncodedContent(data)); }
/// <summary> /// Executes the BLAST search request. /// </summary> /// <param name="bp">Parameters</param> /// <param name="token">Cancellation token</param> /// <returns>XML data as a string</returns> public async Task<Stream> ExecuteAsync(BlastRequestParameters bp, CancellationToken token) { if (string.IsNullOrWhiteSpace(this.EndPoint)) throw new ArgumentException("EndPoint must be set."); if (this.TimeoutInSeconds <= 0) throw new ArgumentException("Timeout must be >= 1"); this.Log("Posting request to {0}", this.EndPoint); var content = this.BuildRequest(bp); this.Log(await content.ReadAsStringAsync()); var client = new HttpClient(); var result = await client.PostAsync(this.EndPoint, content, token); result.EnsureSuccessStatusCode(); this.Log("Reading initial response - looking for Request Id."); string response = await result.Content.ReadAsStringAsync(); if (string.IsNullOrWhiteSpace(response)) { this.Log("Failed to find Request Id in: {0}", response); throw new HttpRequestException("No data returned."); } // Get the request ID and Estimated time to completion Regex ridExpr = new Regex(@"QBlastInfoBegin\s+RID = (\w+)\s+RTOE = (\w+)"); var matches = ridExpr.Matches(response); if (matches.Count != 1 || matches[0].Groups.Count != 3) throw new HttpRequestException("Unrecognized format returned, no Request Id located."); var match = matches[0]; string rid = match.Groups[1].Value; string ttl = match.Groups[2].Value; this.Log("RequestId: {0}, Estimated Time to Completion: {1} secs.", rid, ttl); // Calculate our max time. DateTime timeoutValue = DateTime.Now.AddSeconds(this.TimeoutInSeconds); // Get the time to completion - we'll wait that long before // starting our polling. int seconds; if (Int32.TryParse(ttl, out seconds)) { seconds = Math.Min(seconds, this.TimeoutInSeconds); this.Log("Waiting for {0} seconds", seconds); await Task.Delay(seconds * 1000, token); } Regex statusExpr = new Regex(@"QBlastInfoBegin\s+Status=(\w+)"); // Begin our polling operation; this isn't the most efficient, but NCBI doesn't // provide any other mechanism. while (true) { // Check on our request. this.Log("Checking on request {0}", rid); response = await client.GetStringAsync( string.Format("{0}?CMD=Get&FORMAT_OBJECT=SearchInfo&RID={1}", this.EndPoint, rid)); var statusMatch = statusExpr.Matches(response); if (statusMatch.Count == 1) { string state = statusMatch[0].Groups[1].Value; this.Log("Processing response: {0}", response); if (state == "FAILED") throw new Exception("Search " + rid + " failed; please report to [email protected]."); if (state == "UNKNOWN") throw new OperationCanceledException("Search " + rid + " expired."); if (state == "READY") { Regex hasHitsExpr = new Regex(@"QBlastInfoBegin\s+ThereAreHits=yes"); if (!hasHitsExpr.IsMatch(response)) { return null; // no hits } break; } } else { this.Log("Did not find Status in response: {0}", response); } // Go to sleep and try again. this.Log("Waiting 2 seconds.", response); await Task.Delay(2000, token); // Check at the end so we get at least one attempt. token.ThrowIfCancellationRequested(); // Check the timeout value. if (DateTime.Now > timeoutValue) throw new OperationCanceledException("Timeout value exceeded."); } // Retrieve the response. this.Log("Retrieving final response for Request Id {0}", rid); return await client.GetStreamAsync( string.Format("{0}?CMD=Get&FORMAT_TYPE=XML&RID={1}", this.EndPoint, rid)); }
/// <summary> /// Build the HTTP content for the request based on the parameters /// </summary> /// <returns>The request.</returns> public HttpContent BuildRequest(BlastRequestParameters blastParams) { if (string.IsNullOrWhiteSpace(blastParams.Database)) throw new ArgumentException("Database must be supplied."); if (string.IsNullOrWhiteSpace(blastParams.Program)) throw new ArgumentException("Program must be supplied."); if (blastParams.Sequences.Count == 0) throw new ArgumentException("Must have at least one sequence."); // Check that all sequences are same alphabet if (blastParams.Sequences.Count > 1) { ISequence primary = blastParams.Sequences[0]; for (int i = 1; i < blastParams.Sequences.Count; i++) { if (!Alphabets.CheckIsFromSameBase(primary.Alphabet, blastParams.Sequences[i].Alphabet)) throw new ArgumentException("Sequences must all share the same base alphabet."); } } var data = new List<KeyValuePair<string, string>> { this.CreateKVP("CMD", "Put") }; if (blastParams.Program == BlastProgram.Megablast) { data.Add(this.CreateKVP("PROGRAM", BlastProgram.Blastn)); data.Add(this.CreateKVP("MEGABLAST", "ON")); } else data.Add(this.CreateKVP("PROGRAM", blastParams.Program)); data.Add(this.CreateKVP("DATABASE", blastParams.Database)); data.AddRange(blastParams.ExtraParameters); // Add the sequences. StringBuilder sb = new StringBuilder(); foreach (var seq in blastParams.Sequences) sb.Append(seq.ConvertToString()); data.Add(this.CreateKVP("QUERY", sb.ToString())); return new FormUrlEncodedContent(data); }
/// <summary> /// Initializes a new instance of the WebServiceInputEventArgs class /// </summary> /// <param name="serviceName">Web service name</param> /// <param name="parameters">the selected service parameters</param> public WebServiceInputEventArgs(string serviceName, BlastRequestParameters parameters) { this.ServiceName = serviceName; this.Parameters = parameters; }
/// <summary> /// This event is fired on click of the submit button on the dialog, /// this would validate the parameters accordingly and on success would initiate adding /// of the parameters to the given service parameters /// </summary> /// <param name="sender">submit button</param> /// <param name="e">Event Data</param> private void OnBtnSubmitClick(object sender, RoutedEventArgs e) { var serviceParam = new BlastRequestParameters(); bool valid = this.AddServiceParams(ref serviceParam, this.firstStk); if (valid) valid = this.AddServiceParams(ref serviceParam, this.secondStk); if (valid) valid = this.AddServiceParams(ref serviceParam, this.thirdColumnParams); if (valid) valid = this.AddServiceParams(ref serviceParam, this.commonParamsStk); if (valid && this.serviceParams.Visibility == Visibility.Visible) valid = this.AddServiceParams(ref serviceParam, this.serviceParams); if (valid) { var args = new WebServiceInputEventArgs(this.serviceName, serviceParam); this.WebServiceInputArgs = args; if (this.ExecuteSearch != null) { this.ExecuteSearch.Invoke(this, args); this.Close(); } else this.Close(); } }
/// <summary> /// This method validates the gap cost input /// and on success adds the gap cost to the service parameters /// </summary> /// <param name="serviceParam">service param to add the param</param> /// <returns>whether the gap cost was valid and added or not</returns> private bool CheckNAddGapCostField(ref BlastRequestParameters serviceParam) { int number; if (!Int32.TryParse(this.gapOpenTxt.Text, out number) && number != 0) { MessageBox.Show( Properties.Resources.INVALID_TEXT + GAPCOSTS + Properties.Resources.VALUE_TEXT, Properties.Resources.CAPTION, MessageBoxButton.OK, MessageBoxImage.Error); return false; } if (!Int32.TryParse(this.gapOpenTxt.Text, out number) && number != 0) { MessageBox.Show( Properties.Resources.INVALID_TEXT + GAPCOSTS + Properties.Resources.VALUE_TEXT, Properties.Resources.CAPTION, MessageBoxButton.OK, MessageBoxImage.Error); return false; } serviceParam.ExtraParameters.Add(GAPCOSTS, this.gapOpenTxt.Text + " " + this.gapExtendedTxt.Text); return true; }
/// <summary> /// This method would add service params to the given service param, /// The would get all the children items from the stack panel and would read the param values /// and add to the search service parameters. /// </summary> /// <param name="serviceParam">Service parameter</param> /// <param name="panel">Stack panel</param> /// <returns>returns whether the given param was added or not</returns> private bool AddServiceParams(ref BlastRequestParameters serviceParam, StackPanel panel) { bool valid = true; foreach (UIElement element in panel.Children) { var txtBox = element as TextBox; var lstBox = element as ListBox; var chkbox = element as CheckBox; if (txtBox != null) { valid = AddValidServiceParams(ref serviceParam, txtBox.Tag.ToString(), txtBox.Text); } else if (lstBox != null) { } else if (chkbox != null) { } else { var combo = element as ComboBox; if (combo != null && combo.Visibility == Visibility.Visible) { valid = AddValidServiceParams( ref serviceParam, combo.Tag.ToString(), combo.SelectedValue.ToString()); } } if (!valid) { break; } } // checks the gap cost field if (valid) { valid = this.CheckNAddGapCostField(ref serviceParam); } return valid; }
/// <summary> /// This method would validate and add the params to the service /// parameters for the requested search /// </summary> /// <param name="serviceParam">Service parameter</param> /// <param name="paramName">Param name</param> /// <param name="paramValue">Param value</param> /// <returns>whether the parameter was valid</returns> private static bool AddValidServiceParams(ref BlastRequestParameters serviceParam, string paramName, string paramValue) { return false; }
/// <summary> /// Executes the BLAST search request. /// </summary> /// <param name="bp">Parameters</param> /// <param name="token">Cancellation token</param> /// <returns>XML data as a string</returns> public async Task <Stream> ExecuteAsync(BlastRequestParameters bp, CancellationToken token) { if (string.IsNullOrWhiteSpace(this.EndPoint)) { throw new ArgumentException("EndPoint must be set."); } if (this.TimeoutInSeconds <= 0) { throw new ArgumentException("Timeout must be >= 1"); } this.Log("Posting request to {0}", this.EndPoint); var content = this.BuildRequest(bp); this.Log(await content.ReadAsStringAsync()); var client = new HttpClient(); var result = await client.PostAsync(this.EndPoint, content, token); result.EnsureSuccessStatusCode(); this.Log("Reading initial response - looking for Request Id."); string response = await result.Content.ReadAsStringAsync(); if (string.IsNullOrWhiteSpace(response)) { this.Log("Failed to find Request Id in: {0}", response); throw new HttpRequestException("No data returned."); } // Get the request ID and Estimated time to completion Regex ridExpr = new Regex(@"QBlastInfoBegin\s+RID = (\w+)\s+RTOE = (\w+)"); var matches = ridExpr.Matches(response); if (matches.Count != 1 || matches[0].Groups.Count != 3) { throw new HttpRequestException("Unrecognized format returned, no Request Id located."); } var match = matches[0]; string rid = match.Groups[1].Value; string ttl = match.Groups[2].Value; this.Log("RequestId: {0}, Estimated Time to Completion: {1} secs.", rid, ttl); // Calculate our max time. DateTime timeoutValue = DateTime.Now.AddSeconds(this.TimeoutInSeconds); // Get the time to completion - we'll wait that long before // starting our polling. int seconds; if (Int32.TryParse(ttl, out seconds)) { seconds = Math.Min(seconds, this.TimeoutInSeconds); this.Log("Waiting for {0} seconds", seconds); await Task.Delay(seconds * 1000, token); } Regex statusExpr = new Regex(@"QBlastInfoBegin\s+Status=(\w+)"); // Begin our polling operation; this isn't the most efficient, but NCBI doesn't // provide any other mechanism. while (true) { // Check on our request. this.Log("Checking on request {0}", rid); response = await client.GetStringAsync( string.Format("{0}?CMD=Get&FORMAT_OBJECT=SearchInfo&RID={1}", this.EndPoint, rid)); var statusMatch = statusExpr.Matches(response); if (statusMatch.Count == 1) { string state = statusMatch[0].Groups[1].Value; this.Log("Processing response: {0}", response); if (state == "FAILED") { throw new Exception("Search " + rid + " failed; please report to [email protected]."); } if (state == "UNKNOWN") { throw new OperationCanceledException("Search " + rid + " expired."); } if (state == "READY") { Regex hasHitsExpr = new Regex(@"QBlastInfoBegin\s+ThereAreHits=yes"); if (!hasHitsExpr.IsMatch(response)) { return(null); // no hits } break; } } else { this.Log("Did not find Status in response: {0}", response); } // Go to sleep and try again. this.Log("Waiting 2 seconds.", response); await Task.Delay(2000, token); // Check at the end so we get at least one attempt. token.ThrowIfCancellationRequested(); // Check the timeout value. if (DateTime.Now > timeoutValue) { throw new OperationCanceledException("Timeout value exceeded."); } } // Retrieve the response. this.Log("Retrieving final response for Request Id {0}", rid); return(await client.GetStreamAsync( string.Format("{0}?CMD=Get&FORMAT_TYPE=XML&RID={1}", this.EndPoint, rid))); }