From 6509663f279b321d8c019b3c0fa76e4457733c56 Mon Sep 17 00:00:00 2001 From: Michael Tran Date: Mon, 15 Apr 2019 20:44:15 -0400 Subject: [PATCH 1/6] rename --- RedcapApi/Api/Redcap.cs | 12 ++++++------ RedcapApi/Utilities/Utils.cs | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/RedcapApi/Api/Redcap.cs b/RedcapApi/Api/Redcap.cs index a355fbe..7e4e225 100644 --- a/RedcapApi/Api/Redcap.cs +++ b/RedcapApi/Api/Redcap.cs @@ -1116,7 +1116,7 @@ public async Task ImportFileAsync(string token, string record, string fi _fileContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); payload.Add(_fileContent, "file", _fileName); } - return await this.SendRequestAsync(payload, _uri); + return await this.SendPostRequestAsync(payload, _uri); } catch (Exception Ex) { @@ -1194,7 +1194,7 @@ public async Task ImportFileAsync(string token, Content content, RedcapA _fileContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); payload.Add(_fileContent, "file", _fileName); } - return await this.SendRequestAsync(payload, _uri); + return await this.SendPostRequestAsync(payload, _uri); } catch (Exception Ex) { @@ -1251,7 +1251,7 @@ public async Task DeleteFileAsync(string token, string record, string fi payload.Add(new StringContent(repeatInstance), "repeat_instance"); } - return await this.SendRequestAsync(payload, _uri); + return await this.SendPostRequestAsync(payload, _uri); } catch (Exception Ex) { @@ -1309,7 +1309,7 @@ public async Task DeleteFileAsync(string token, Content content, RedcapA payload.Add(new StringContent(repeatInstance), "repeat_instance"); } - return await this.SendRequestAsync(payload, _uri); + return await this.SendPostRequestAsync(payload, _uri); } catch (Exception Ex) { @@ -5436,7 +5436,7 @@ public async Task ImportFileAsync(string record, string field, string ev _fileContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); payload.Add(_fileContent, "file", _fileName); } - _responseMessage = await this.SendRequestAsync(payload, _uri); + _responseMessage = await this.SendPostRequestAsync(payload, _uri); return _responseMessage; } catch (Exception Ex) @@ -5481,7 +5481,7 @@ public async Task DeleteFileAsync(string record, string field, string ev // add repeat instrument params if available payload.Add(new StringContent(_repeatInstance), "repeat_instance"); } - _responseMessage = await this.SendRequestAsync(payload, _uri); + _responseMessage = await this.SendPostRequestAsync(payload, _uri); return _responseMessage; } catch (Exception Ex) diff --git a/RedcapApi/Utilities/Utils.cs b/RedcapApi/Utilities/Utils.cs index bda01dd..0522ad4 100644 --- a/RedcapApi/Utilities/Utils.cs +++ b/RedcapApi/Utilities/Utils.cs @@ -209,10 +209,10 @@ public static async Task ConvertIntArraytoString(this RedcapApi redcapAp try { StringBuilder builder = new StringBuilder(); - foreach (var v in inputArray) + foreach (var intValue in inputArray) { - builder.Append(v); + builder.Append(intValue); // We do not need to append the , if less than or equal to a single string if (inputArray.Length <= 1) { @@ -597,7 +597,7 @@ public static async Task GetStreamContentAsync(this RedcapApi redcapApi, /// data /// URI of the api instance /// string - public static async Task SendRequestAsync(this RedcapApi redcapApi, MultipartFormDataContent payload, Uri uri) + public static async Task SendPostRequestAsync(this RedcapApi redcapApi, MultipartFormDataContent payload, Uri uri) { try { From 329b0b49d50735ba794c95d5688958f7bbf24fec Mon Sep 17 00:00:00 2001 From: Michael Tran Date: Mon, 15 Apr 2019 21:10:49 -0400 Subject: [PATCH 2/6] Update Redcap.cs update doc --- RedcapApi/Api/Redcap.cs | 46 +++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/RedcapApi/Api/Redcap.cs b/RedcapApi/Api/Redcap.cs index 7e4e225..dd725d6 100644 --- a/RedcapApi/Api/Redcap.cs +++ b/RedcapApi/Api/Redcap.cs @@ -80,6 +80,7 @@ public RedcapApi(string redcapApiUrl) #region Arms /// /// API Version 1.0.0+ ** + /// From Redcap Version 4.7.0 /// Export Arms /// This method allows you to export the Arms for a project /// NOTE: This only works for longitudinal projects. @@ -133,8 +134,10 @@ public async Task ExportArmsAsync(string token, ReturnFormat returnForma } } + /// /// API Version 1.0.0+ ** + /// From Redcap Version 4.7.0 /// Export Arms /// This method allows you to export the Arms for a project /// NOTE: This only works for longitudinal projects. @@ -192,7 +195,7 @@ public async Task ExportArmsAsync(string token, Content content, ReturnF /// /// API Version 1.0.0+ - /// From Redcap Version 6.11.0 + /// From Redcap Version 4.7.0 /// /// Import Arms /// This method allows you to import Arms into a project or to rename existing Arms in a project. @@ -251,7 +254,7 @@ public async Task ImportArmsAsync(string token, Override overrideBhav /// /// API Version 1.0.0+ - /// From Redcap Version 6.11.0 + /// From Redcap Version 4.7.0 /// /// Import Arms /// This method allows you to import Arms into a project or to rename existing Arms in a project. @@ -311,7 +314,7 @@ public async Task ImportArmsAsync(string token, Content content, Over /// /// API Version 1.0.0+ - /// From Redcap Version 6.11.0 + /// From Redcap Version 4.7.0 /// /// Delete Arms /// This method allows you to delete Arms from a project. @@ -364,7 +367,7 @@ public async Task DeleteArmsAsync(string token, string[] arms) /// /// API Version 1.0.0+ - /// From Redcap Version 6.11.0 + /// From Redcap Version 4.7.0 /// /// Delete Arms /// This method allows you to delete Arms from a project. @@ -421,7 +424,7 @@ public async Task DeleteArmsAsync(string token, Content content, RedcapA /// /// API Version 1.0.0+ - /// From Redcap Version 6.11.0 + /// From Redcap Version 4.7.0 /// /// Export Events /// This method allows you to export the events for a project @@ -1404,6 +1407,7 @@ public async Task ExportInstrumentsAsync(string token, Content content = /// /// API Version 1.0.0+ + /// From Redcap Version 6.4.0 /// Export PDF file of Data Collection Instruments (either as blank or with data) /// This method allows you to export a PDF file for any of the following: 1) a single data collection instrument (blank), 2) all instruments (blank), 3) a single instrument (with data from a single record), 4) all instruments (with data from a single record), or 5) all instruments (with data from ALL records). /// This is the exact same PDF file that is downloadable from a project's data entry form in the web interface, and additionally, the user's privileges with regard to data exports will be applied here just like they are when downloading the PDF in the web interface (e.g., if they have de-identified data export rights, then it will remove data from certain fields in the PDF). @@ -1466,6 +1470,7 @@ public async Task ExportPDFInstrumentsAsync(string token, string recordI /// /// API Version 1.0.0+ + /// From Redcap Version 6.4.0 /// Export PDF file of Data Collection Instruments (either as blank or with data) /// This method allows you to export a PDF file for any of the following: 1) a single data collection instrument (blank), 2) all instruments (blank), 3) a single instrument (with data from a single record), 4) all instruments (with data from a single record), or 5) all instruments (with data from ALL records). /// This is the exact same PDF file that is downloadable from a project's data entry form in the web interface, and additionally, the user's privileges with regard to data exports will be applied here just like they are when downloading the PDF in the web interface (e.g., if they have de-identified data export rights, then it will remove data from certain fields in the PDF). @@ -1529,6 +1534,7 @@ public async Task ExportPDFInstrumentsAsync(string token, Content conten /// /// API Version 1.0.0+ + /// From Redcap Version 6.4.0 /// **Allows for file download to a path.** /// Export PDF file of Data Collection Instruments (either as blank or with data) /// This method allows you to export a PDF file for any of the following: 1) a single data collection instrument (blank), 2) all instruments (blank), 3) a single instrument (with data from a single record), 4) all instruments (with data from a single record), or 5) all instruments (with data from ALL records). @@ -1601,7 +1607,7 @@ public async Task ExportPDFInstrumentsAsync(string token, string recordI /// /// API Version 1.0.0+ - /// From Redcap Version 6.11.0 + /// From Redcap Version 4.7.0 /// /// Export Instrument-Event Mappings /// This method allows you to export the instrument-event mappings for a project (i.e., how the data collection instruments are designated for certain events in a longitudinal project). @@ -1653,7 +1659,7 @@ public async Task ExportInstrumentMappingAsync(string token, ReturnForma /// /// API Version 1.0.0+ - /// From Redcap Version 6.11.0 + /// From Redcap Version 4.7.0 /// /// Export Instrument-Event Mappings /// This method allows you to export the instrument-event mappings for a project (i.e., how the data collection instruments are designated for certain events in a longitudinal project). @@ -1706,7 +1712,7 @@ public async Task ExportInstrumentMappingAsync(string token, Content con /// /// API Version 1.0.0+ - /// From Redcap Version 6.11.0 + /// FFrom Redcap Version 4.7.0 /// /// Import Instrument-Event Mappings /// This method allows you to import Instrument-Event Mappings into a project (this corresponds to the 'Designate Instruments for My Events' page in the project). @@ -1759,7 +1765,7 @@ public async Task ImportInstrumentMappingAsync(string token, ReturnFo /// /// API Version 1.0.0+ - /// From Redcap Version 6.11.0 + /// From Redcap Version 4.7.0 /// /// Import Instrument-Event Mappings /// This method allows you to import Instrument-Event Mappings into a project (this corresponds to the 'Designate Instruments for My Events' page in the project). @@ -1814,6 +1820,7 @@ public async Task ImportInstrumentMappingAsync(string token, Content #region Metadata /// /// API Version 1.0.0+ + /// From Redcap Version 3.4.0+ /// Export Metadata (Data Dictionary) /// This method allows you to export the metadata for a project /// @@ -1870,6 +1877,7 @@ public async Task ExportMetaDataAsync(string token, Content content = Co } /// /// API Version 1.0.0+ + /// From Redcap Version 3.4.0+ /// Export Metadata (Data Dictionary) /// This method allows you to export the metadata for a project /// @@ -3427,6 +3435,7 @@ public async Task ExportRedcapVersionAsync(string token, ReturnFormat fo #region Surveys /// /// API Version 1.0.0+ + /// From Redcap Version 6.4.0 /// Export a Survey Link for a Participant /// This method returns a unique survey link (i.e., a URL) in plain text format for a specified record and data collection instrument (and event, if longitudinal) in a project. If the user does not have 'Manage Survey Participants' privileges, they will not be able to use this method, and an error will be returned. If the specified data collection instrument has not been enabled as a survey in the project, an error will be returned. /// @@ -3474,6 +3483,7 @@ public async Task ExportSurveyLinkAsync(string token, string record, str /// /// API Version 1.0.0+ + /// From Redcap Version 6.4.0 /// Export a Survey Link for a Participant /// This method returns a unique survey link (i.e., a URL) in plain text format for a specified record and data collection instrument (and event, if longitudinal) in a project. If the user does not have 'Manage Survey Participants' privileges, they will not be able to use this method, and an error will be returned. If the specified data collection instrument has not been enabled as a survey in the project, an error will be returned. /// @@ -3610,9 +3620,10 @@ public async Task ExportSurveyParticipantsAsync(string token, Content co return Ex.Message; } } + /// /// API Version 1.0.0+ - /// From Redcap Version 6.11.0 + /// From Redcap Version 6.4.0 /// /// Export a Survey Queue Link for a Participant /// This method returns a unique Survey Queue link (i.e., a URL) in plain text format for the specified record in a project that is utilizing the Survey Queue feature. If the user does not have 'Manage Survey Participants' privileges, they will not be able to use this method, and an error will be returned. If the Survey Queue feature has not been enabled in the project, an error will be @@ -3654,7 +3665,7 @@ public async Task ExportSurveyQueueLinkAsync(string token, string record /// /// API Version 1.0.0+ - /// From Redcap Version 6.11.0 + /// From Redcap Version 6.4.0 /// /// Export a Survey Queue Link for a Participant /// This method returns a unique Survey Queue link (i.e., a URL) in plain text format for the specified record in a project that is utilizing the Survey Queue feature. If the user does not have 'Manage Survey Participants' privileges, they will not be able to use this method, and an error will be returned. If the Survey Queue feature has not been enabled in the project, an error will be @@ -3694,7 +3705,10 @@ public async Task ExportSurveyQueueLinkAsync(string token, Content conte return Ex.Message; } } + /// + /// API Version 1.0.0+ + /// From Redcap Version 6.4.0 /// Export a Survey Return Code for a Participant /// This method returns a unique Return Code in plain text format for a specified record and data collection instrument (and event, if longitudinal) in a project. If the user does not have 'Manage Survey Participants' privileges, they will not be able to use this method, and an error will be returned. If the specified data collection instrument has not been enabled as a survey in the project or does not have the 'Save and Return Later' feature enabled, an error will be returned. /// @@ -3743,6 +3757,8 @@ public async Task ExportSurveyReturnCodeAsync(string token, string recor } /// + /// API Version 1.0.0+ + /// From Redcap Version 6.4.0 /// Export a Survey Return Code for a Participant /// This method returns a unique Return Code in plain text format for a specified record and data collection instrument (and event, if longitudinal) in a project. If the user does not have 'Manage Survey Participants' privileges, they will not be able to use this method, and an error will be returned. If the specified data collection instrument has not been enabled as a survey in the project or does not have the 'Save and Return Later' feature enabled, an error will be returned. /// @@ -3794,7 +3810,7 @@ public async Task ExportSurveyReturnCodeAsync(string token, Content cont #region Users & User Privileges /// /// API Version 1.0.0+ - /// From Redcap Version 6.11.0 + /// From Redcap Version 4.7.0 /// /// Export Users /// This method allows you to export the list of users for a project, including their user privileges and also email address, first name, and last name. Note: If the user has been assigned to a user role, it will return the user with the role's defined privileges. @@ -3845,7 +3861,7 @@ public async Task ExportUsersAsync(string token, ReturnFormat format = R /// /// API Version 1.0.0+ - /// From Redcap Version 6.11.0 + /// From Redcap Version 4.7.0 /// /// Export Users /// This method allows you to export the list of users for a project, including their user privileges and also email address, first name, and last name. Note: If the user has been assigned to a user role, it will return the user with the role's defined privileges. @@ -3897,7 +3913,7 @@ public async Task ExportUsersAsync(string token, Content content = Conte /// /// API Version 1.0.0+ - /// From Redcap Version 6.11.0 + /// From Redcap Version 4.7.0 /// /// Import Users /// This method allows you to import new users into a project while setting their user privileges, or update the privileges of existing users in the project. @@ -3972,7 +3988,7 @@ public async Task ImportUsersAsync(string token, List data, Return /// /// API Version 1.0.0+ - /// From Redcap Version 6.11.0 + /// From Redcap Version 4.7.0 /// /// Import Users /// This method allows you to import new users into a project while setting their user privileges, or update the privileges of existing users in the project. From 6bf66b240b00d3e529049df82e45ad0317462c38 Mon Sep 17 00:00:00 2001 From: Michael Tran Date: Wed, 6 Nov 2019 14:04:23 -0500 Subject: [PATCH 3/6] Update Program.cs refactoring demo --- RedcapApiDemo/Program.cs | 89 +++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 32 deletions(-) diff --git a/RedcapApiDemo/Program.cs b/RedcapApiDemo/Program.cs index 5c5867d..46d4ca4 100644 --- a/RedcapApiDemo/Program.cs +++ b/RedcapApiDemo/Program.cs @@ -21,21 +21,7 @@ public class Demographic } class Program { - /* - * Change this token for your demo project - * Using one created from a local dev instance - */ - private const string _token = "A8E6949EF4380F1111C66D5374E1AE6C"; - /* - * Change this token for your demo project - * Using one created from a local dev instance - */ - private const string _superToken = "92F719F0EC97783D06B0E0FF49DC42DDA2247BFDC6759F324EE0D710FCA87C33"; - /* - * Using a local redcap development instsance - */ - private const string _uri = "http://localhost/redcap/api/"; - static void Main(string[] args) + public static void Main(string[] args) { /* * This is a demo. This program provides a demonstration of potential calls using the API library. @@ -53,12 +39,7 @@ static void Main(string[] args) * This allows the upload file method to upload files * */ - - /* - * Output to console - */ - Console.WriteLine("Starting Redcap Api Demo.."); - Console.WriteLine("Please make sure you include a working redcap api token."); + InitializeDemo(); /* * Start a new instance of Redcap APi @@ -151,6 +132,39 @@ static void Main(string[] args) + + } + static void InitializeDemo() + { + /* + * Change this token for your demo project + * Using one created from a local dev instance + */ + string _token = string.Empty; + /* + * Change this token for your demo project + * Using one created from a local dev instance + */ + string _superToken = "92F719F0EC97783D06B0E0FF49DC42DDA2247BFDC6759F324EE0D710FCA87C33"; + /* + * Using a local redcap development instsance + */ + string _uri = string.Empty; + var fieldName = "protocol_upload"; + var eventName = "event_1_arm_1"; + + /* + * Output to console + */ + Console.WriteLine("Starting Redcap Api Demo.."); + Console.WriteLine("Please make sure you include a working redcap api token."); + Console.WriteLine("Enter your redcap instance uri, example: http://localhost/redcap"); + _uri = Console.ReadLine(); + _uri = _uri + "/api/"; + Console.WriteLine("Enter your api token for the project to test: "); + var token = Console.ReadLine(); + _token = token; + Console.WriteLine("-----------------------------Starting API Version 1.0.5+-------------"); Console.WriteLine("Starting demo for API Version 1.0.0+"); Console.WriteLine("----------------------------Press Enter to Continue-------------"); @@ -159,20 +173,20 @@ static void Main(string[] args) Console.WriteLine("Creating a new instance of RedcapApi"); var redcap_api_1_0_7 = new RedcapApi(_uri); - Console.WriteLine($"Using {_uri} for redcap api endpoint."); + Console.WriteLine($"Using {_uri.ToString()} for redcap api endpoint."); #region ImportRecordsAsync() Console.WriteLine("Calling ImportRecordsAsync() . . ."); /* * Create a list of object of type instrument or fields. Add its properties then add it to the list. * record_id is required - */ + */ var data = new List { new Demographic { FirstName = "Jon", LastName = "Doe", RecordId = "1" } }; - Console.WriteLine($"Importing record {string.Join(",", data.Select(x=>x.RecordId).ToList())} . . ."); + Console.WriteLine($"Importing record {string.Join(",", data.Select(x => x.RecordId).ToList())} . . ."); var ImportRecordsAsync = redcap_api_1_0_7.ImportRecordsAsync(_token, Content.Record, ReturnFormat.json, RedcapDataType.flat, OverwriteBehavior.normal, false, data, "MDY", ReturnContent.count, OnErrorFormat.json).Result; var ImportRecordsAsyncData = JsonConvert.DeserializeObject(ImportRecordsAsync); Console.WriteLine($"ImportRecordsAsync Result: {ImportRecordsAsyncData}"); @@ -194,7 +208,7 @@ static void Main(string[] args) #endregion DeleteRecordsAsync() #region ExportArmsAsync() - var arms = new string[] {}; + var arms = new string[] { }; Console.WriteLine("Calling ExportArmsAsync()"); var ExportArmsAsyncResult = redcap_api_1_0_7.ExportArmsAsync(_token, Content.Arm, ReturnFormat.json, arms, OnErrorFormat.json).Result; Console.WriteLine($"ExportArmsAsyncResult: {ExportArmsAsyncResult}"); @@ -204,7 +218,7 @@ static void Main(string[] args) Console.ReadLine(); #region ImportArmsAsync() - var ImportArmsAsyncData = new List{ new RedcapArm {ArmNumber = "1", Name = "hooo" }, new RedcapArm { ArmNumber = "2", Name = "heee" }, new RedcapArm { ArmNumber = "3", Name = "hawww" } }; + var ImportArmsAsyncData = new List { new RedcapArm { ArmNumber = "1", Name = "hooo" }, new RedcapArm { ArmNumber = "2", Name = "heee" }, new RedcapArm { ArmNumber = "3", Name = "hawww" } }; Console.WriteLine("Calling ImportArmsAsync()"); var ImportArmsAsyncResult = redcap_api_1_0_7.ImportArmsAsync(_token, Content.Arm, Override.False, RedcapAction.Import, ReturnFormat.json, ImportArmsAsyncData, OnErrorFormat.json).Result; Console.WriteLine($"ImportArmsAsyncResult: {ImportArmsAsyncResult}"); @@ -214,7 +228,7 @@ static void Main(string[] args) Console.ReadLine(); #region DeleteArmsAsync() - var DeleteArmsAsyncData = new string[] {"3"}; + var DeleteArmsAsyncData = new string[] { "3" }; Console.WriteLine("Calling DeleteArmsAsync()"); var DeleteArmsAsyncResult = redcap_api_1_0_7.DeleteArmsAsync(_token, Content.Arm, RedcapAction.Delete, DeleteArmsAsyncData).Result; Console.WriteLine($"DeleteArmsAsyncResult: {DeleteArmsAsyncResult}"); @@ -266,7 +280,7 @@ static void Main(string[] args) #region DeleteEventsAsync() var DeleteEventsAsyncData = new string[] { "baseline_arm_1" }; Console.WriteLine("Calling DeleteEventsAsync()"); - var DeleteEventsAsyncResult = redcap_api_1_0_7.DeleteEventsAsync(_token, Content.Event, RedcapAction.Delete, DeleteEventsAsyncData ).Result; + var DeleteEventsAsyncResult = redcap_api_1_0_7.DeleteEventsAsync(_token, Content.Event, RedcapAction.Delete, DeleteEventsAsyncData).Result; Console.WriteLine($"DeleteEventsAsyncResult: {DeleteEventsAsyncResult}"); #endregion DeleteEventsAsync() @@ -296,7 +310,7 @@ static void Main(string[] args) Console.WriteLine("----------------------------Press Enter to Continue-------------"); Console.ReadLine(); - + #region ExportFileAsync() Console.WriteLine($"Calling ExportFileAsync(), {fileName} for field name {fieldName}, not save the file."); var ExportFileAsyncResult = redcap_api_1_0_7.ExportFileAsync(_token, Content.File, RedcapAction.Export, recordId, fieldName, eventName, null, OnErrorFormat.json).Result; @@ -362,7 +376,7 @@ static void Main(string[] args) Console.ReadLine(); #region ImportInstrumentMappingAsync() - var importInstrumentMappingData = new List{new FormEventMapping {arm_num = "1", unique_event_name = "clinical_arm_1", form= "demographics" } }; + var importInstrumentMappingData = new List { new FormEventMapping { arm_num = "1", unique_event_name = "clinical_arm_1", form = "demographics" } }; Console.WriteLine($"Calling ImportInstrumentMappingAsync()"); var ImportInstrumentMappingAsyncResult = redcap_api_1_0_7.ImportInstrumentMappingAsync(_token, Content.FormEventMapping, ReturnFormat.json, importInstrumentMappingData, OnErrorFormat.json).Result; Console.WriteLine($"ImportInstrumentMappingAsyncResult: {ImportInstrumentMappingAsyncResult}"); @@ -394,10 +408,10 @@ static void Main(string[] args) Console.ReadLine(); #region CreateProjectAsync() - var projectData = new List { new RedcapProject {project_title = "Amazing Project ", purpose = ProjectPurpose.Other, purpose_other = "Test"} }; + var projectData = new List { new RedcapProject { project_title = "Amazing Project ", purpose = ProjectPurpose.Other, purpose_other = "Test" } }; Console.WriteLine($"Calling CreateProjectAsync(), creating a new project with Amazing Project as title, purpose 1 (other) "); Console.WriteLine($"-----------------------Notice the use of SUPER TOKEN------------------------"); - var CreateProjectAsyncResult = redcap_api_1_0_7.CreateProjectAsync(_superToken,Content.Project, ReturnFormat.json, projectData, OnErrorFormat.json, null).Result; + var CreateProjectAsyncResult = redcap_api_1_0_7.CreateProjectAsync(_superToken, Content.Project, ReturnFormat.json, projectData, OnErrorFormat.json, null).Result; Console.WriteLine($"CreateProjectAsyncResult: {CreateProjectAsyncResult}"); #endregion CreateProjectAsync() Console.WriteLine("----------------------------Press Enter to Continue-------------"); @@ -421,6 +435,17 @@ static void Main(string[] args) Console.WriteLine("----------------------------Demo completed! Press Enter to Exit-------------"); Console.ReadLine(); + #region ExportRecordsAsync() + Console.WriteLine($"Calling ExportRecordsAsync()"); + Console.WriteLine($"Using record 1"); + Console.WriteLine($"Using instrumentname = demographics"); + var instrumentName = new string[] { "demographics" }; + var ExportRecordsAsyncResult = redcap_api_1_0_7.ExportRecordsAsync(_token, Content.Record, ReturnFormat.json, RedcapDataType.flat, null, null, instrumentName).Result; + Console.WriteLine($"ExportRecordsAsyncResult: {ExportProjectInfoAsyncResult}"); + #endregion ExportRecordsAsync() + + Console.WriteLine("----------------------------Demo completed! Press Enter to Exit-------------"); + Console.ReadLine(); } } From edad140b2468302164dc54b9c896d4fd07d73b64 Mon Sep 17 00:00:00 2001 From: Michael Tran Date: Thu, 7 Nov 2019 14:08:00 -0500 Subject: [PATCH 4/6] Update Redcap.csproj add icon --- RedcapApi/Redcap.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/RedcapApi/Redcap.csproj b/RedcapApi/Redcap.csproj index c836f8a..c624d39 100644 --- a/RedcapApi/Redcap.csproj +++ b/RedcapApi/Redcap.csproj @@ -25,6 +25,7 @@ Bug fixes 1.0.7.0 https://github.com/cctrbic/redcap-api/blob/master/LICENSE.md https://github.com/cctrbic/redcap-api/blob/master/LICENSE.md + https://vortex.cctr.vcu.edu/images/ram_crest_160.png false From 0cf327afc2b38bb7793961d17f972665ee8e6e6c Mon Sep 17 00:00:00 2001 From: Michael Tran Date: Mon, 27 Jan 2020 12:26:10 -0500 Subject: [PATCH 5/6] add update from dr01d3r Thanks to @dr01d3r for this contribution --- RedcapApi/Http/CustomFormUrlEncodedContent.cs | 52 +++++++ RedcapApi/Redcap.csproj | 6 +- RedcapApi/Utilities/Utils.cs | 130 +++++------------- RedcapApiDemo/Program.cs | 94 +++++++++++++ RedcapApiDemo/SampleData.cs | 10 ++ 5 files changed, 194 insertions(+), 98 deletions(-) create mode 100644 RedcapApi/Http/CustomFormUrlEncodedContent.cs create mode 100644 RedcapApiDemo/SampleData.cs diff --git a/RedcapApi/Http/CustomFormUrlEncodedContent.cs b/RedcapApi/Http/CustomFormUrlEncodedContent.cs new file mode 100644 index 0000000..bb5dd38 --- /dev/null +++ b/RedcapApi/Http/CustomFormUrlEncodedContent.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; + +namespace Redcap.Http +{ + /// + /// https://stackoverflow.com/a/23740338 + /// + public class CustomFormUrlEncodedContent : ByteArrayContent + { + /// + /// + /// + /// + public CustomFormUrlEncodedContent(IEnumerable> nameValueCollection) + : base(CustomFormUrlEncodedContent.GetContentByteArray(nameValueCollection)) + { + base.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded"); + } + private static byte[] GetContentByteArray(IEnumerable> nameValueCollection) + { + if (nameValueCollection == null) + { + throw new ArgumentNullException("nameValueCollection"); + } + StringBuilder stringBuilder = new StringBuilder(); + foreach (KeyValuePair current in nameValueCollection) + { + if (stringBuilder.Length > 0) + { + stringBuilder.Append('&'); + } + + stringBuilder.Append(CustomFormUrlEncodedContent.Encode(current.Key)); + stringBuilder.Append('='); + stringBuilder.Append(CustomFormUrlEncodedContent.Encode(current.Value)); + } + return Encoding.Default.GetBytes(stringBuilder.ToString()); + } + private static string Encode(string data) + { + if (string.IsNullOrEmpty(data)) + { + return string.Empty; + } + return System.Net.WebUtility.UrlEncode(data).Replace("%20", "+"); + } + } +} \ No newline at end of file diff --git a/RedcapApi/Redcap.csproj b/RedcapApi/Redcap.csproj index c624d39..96bf0f2 100644 --- a/RedcapApi/Redcap.csproj +++ b/RedcapApi/Redcap.csproj @@ -10,8 +10,8 @@ This library allows applications on the .NET platform to make http calls to REDCap instances. Redcap Api Library RedcapAPI - 1.0.7 - 1.0.7.0 + 1.0.8 + 1.0.8.0 redcap api library Additional tests for latest release. Additional methods include: ImportRepeatingInstrumentsAndEvents @@ -22,7 +22,7 @@ Bug fixes Library en - 1.0.7.0 + 1.0.8.0 https://github.com/cctrbic/redcap-api/blob/master/LICENSE.md https://github.com/cctrbic/redcap-api/blob/master/LICENSE.md https://vortex.cctr.vcu.edu/images/ram_crest_160.png diff --git a/RedcapApi/Utilities/Utils.cs b/RedcapApi/Utilities/Utils.cs index 95e9240..6ab611e 100644 --- a/RedcapApi/Utilities/Utils.cs +++ b/RedcapApi/Utilities/Utils.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json; +using Redcap.Http; using Redcap.Models; using Serilog; using System; @@ -644,9 +645,8 @@ public static async Task SendPostRequestAsync(this RedcapApi redcapApi, /// /// data /// URI of the api instance - /// Requests size > 32k chars /// - public static async Task SendPostRequestAsync(this RedcapApi redcapApi, Dictionary payload, Uri uri, bool isLargeDataset = false) + public static async Task SendPostRequestAsync(this RedcapApi redcapApi, Dictionary payload, Uri uri) { try { @@ -666,112 +666,53 @@ public static async Task SendPostRequestAsync(this RedcapApi redcapApi, payload.Remove(pathkey); } - /* - * Encode the values for payload - * Add in ability to process large data set, using StringContent - * Thanks to Ibrahim for pointing this out. - * https://stackoverflow.com/questions/23703735/how-to-set-large-string-inside-httpcontent-when-using-httpclient/23740338 - */ - if (isLargeDataset) + using (var content = new CustomFormUrlEncodedContent(payload)) { - /* - * Send request with large data set - */ - - var serializedPayload = JsonConvert.SerializeObject(payload); - using (var content = new StringContent(serializedPayload, Encoding.UTF8, "application/json")) + using (var response = await client.PostAsync(uri, content)) { - using (var response = await client.PostAsync(uri, content)) + if (response.IsSuccessStatusCode) { - if (response.IsSuccessStatusCode) + // Get the filename so we can save with the name + var headers = response.Content.Headers; + var fileName = headers.ContentType.Parameters.Select(x => x.Value).FirstOrDefault(); + if (!string.IsNullOrEmpty(fileName)) { - // Get the filename so we can save with the name - var headers = response.Content.Headers; - var fileName = headers.ContentType.Parameters.Select(x => x.Value).FirstOrDefault(); - if (!string.IsNullOrEmpty(fileName)) + var contentDisposition = response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { - var contentDisposition = response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") - { - FileName = fileName - }; - } - - if (!string.IsNullOrEmpty(pathValue)) - { - // save the file to a specified location using an extension method - await response.Content.ReadAsFileAsync(fileName, pathValue, true); - _responseMessage = fileName; - } - else - { - _responseMessage = await response.Content.ReadAsStringAsync(); - } - - } - else - { - _responseMessage = await response.Content.ReadAsStringAsync(); + FileName = fileName + }; } - } - } - return _responseMessage; - } - else - { - /* - * Maximum character limit of 32,000 using FormUrlEncodedContent - * Send request using small data set - */ - using (var content = new FormUrlEncodedContent(payload)) - { - using (var response = await client.PostAsync(uri, content)) - { - if (response.IsSuccessStatusCode) + + if (!string.IsNullOrEmpty(pathValue)) { - // Get the filename so we can save with the name - var headers = response.Content.Headers; - var fileName = headers.ContentType.Parameters.Select(x => x.Value).FirstOrDefault(); - if (!string.IsNullOrEmpty(fileName)) + var fileExtension = payload.Where(x => x.Key == "content" && x.Value == "pdf").SingleOrDefault().Value; + if (!string.IsNullOrEmpty(fileExtension)) { - var contentDisposition = response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") - { - FileName = fileName - }; - } - + // pdf + fileName = payload.Where(x => x.Key == "instrument").SingleOrDefault().Value; + // to do , make extensions for various types + // save the file to a specified location using an extension method + await response.Content.ReadAsFileAsync(fileName, pathValue, true, fileExtension); - if (!string.IsNullOrEmpty(pathValue)) - { - var fileExtension = payload.Where(x => x.Key == "content" && x.Value == "pdf").SingleOrDefault().Value; - if (!string.IsNullOrEmpty(fileExtension)) - { - // pdf - fileName = payload.Where(x => x.Key == "instrument").SingleOrDefault().Value; - // to do , make extensions for various types - // save the file to a specified location using an extension method - await response.Content.ReadAsFileAsync(fileName, pathValue, true, fileExtension); - - } - else - { - await response.Content.ReadAsFileAsync(fileName, pathValue, true, fileExtension); - - } - _responseMessage = fileName; } else { - _responseMessage = await response.Content.ReadAsStringAsync(); + await response.Content.ReadAsFileAsync(fileName, pathValue, true, fileExtension); + } + _responseMessage = fileName; } else { _responseMessage = await response.Content.ReadAsStringAsync(); } } + else + { + _responseMessage = await response.Content.ReadAsStringAsync(); + } } - } return _responseMessage; } @@ -781,14 +722,13 @@ public static async Task SendPostRequestAsync(this RedcapApi redcapApi, Log.Error($"{Ex.Message}"); return Empty; } - } - /// - /// Sends http request to api - /// - /// - /// data - /// URI of the api instance - /// string + } /// + /// Sends http request to api + /// + /// + /// data + /// URI of the api instance + /// string public static async Task SendPostRequest(this RedcapApi redcapApi, Dictionary payload, Uri uri) { string responseString; diff --git a/RedcapApiDemo/Program.cs b/RedcapApiDemo/Program.cs index 46d4ca4..7f49949 100644 --- a/RedcapApiDemo/Program.cs +++ b/RedcapApiDemo/Program.cs @@ -18,9 +18,88 @@ public class Demographic [JsonProperty("last_name")] public string LastName { get; set; } + [JsonProperty("bio")] + public string Bio { get; set; } } class Program { + static Random rand = new Random(); + public const string VeryLargeText = @"If I don't make it back, you're the only hope for the Alliance. Luke, don't talk that way. You have a power I--I don't understand and could never have. You're wrong, Leia. You have that power too. In time you'll learn to use it as I have. The Force is strong in my family. My father has it... I have it ...and...my sister has it. Yes. It's you Leia. I know. Somehow...I've always known. Then you know why I have to face him. +I told you to remain on the command ship. A small Rebel force has penetrated the shield and landed on Endor. Yes, I know. My son is with them. Are you sure? I have felt him, my Master. Strange, that I have not. I wonder if your feelings on this matter are clear, Lord Vader. They are clear, my Master. Then you must go to the Sanctuary Moon and wait for them. He will come to me? I have foreseen it. His compassion for you will be his undoing. He will come to you andthen you will bring him before me. As you wish. +Rise, my friend. The Death Star will be completed on schedule. You have done well, Lord Vader. And now I sense you wish to continue your search for young Skywalker. Yes, my Master. Patience, my friend. In time he will seek you out. And when he does, you must bring him before me. He has grown strong. Only together can we turn him to the dark side of the Force. As you wish. Everything is proceeding as I have foreseen. +Greetings, Exalted One. Allow me to introduce myself. I am Luke Skywalker, Jedi Knight and friend to Captain Solo. I know that you are powerful, mighty Jabba, and that your anger with Solo must be equally powerful. I seek an audience with Your Greatness to bargain for Solo's life. With your wisdom, I'm sure that we can work out an arrangement which will be mutually beneficial and enable us to avoid any unpleasant confrontation. As a token of my goodwill, I present to you a gift: these two droids. What did he say? Both are hardworking and will serve you well. +Oh, General Solo, somebody's coming. Oh! Luke! Where's Leia? What? She didn't come back? I thought she was with you. We got separated. Hey, we better go look for her. Take the squad ahead. We'll meet at the shield generator at 0300. Come on, Artoo. We'll need your scanners. Don't worry, Master Luke. We know what to do. And you said it was pretty here. Ugh! +Where is that shuttle going? Shuttle Tydirium, what is your cargo and destination? Parts and technical crew for the forest moon. Do they have a code clearance? It's an older code, sir, but it checks out. I was about to clear them. Shall I hold them? No. Leave them to me. I will deal with them myself. As you wish, my lord. Carry on. They're not goin' for it, Chewie. Shuttle Tydirium, deactivation of the shield will commence immediately. Follow your present course. Okay! I told you it was gonna work. No problem. +Hmm. That face you make. Look I so old to young eyes? No... of course not. I do, yes, I do! Sick have I become. Old and weak. When nine hundred years old you reach, look as good you will not. Hmm? Soon will I rest. Yes, forever sleep. Earned it, I have. Master Yoda, you can't die. Strong am I with the Force... but not that strong! Twilight is upon me and soon night must fall. That is the way of things... the way of the Force. But I need your help. I've come back to complete the training. No more training do you require. Already know you that which you need. Then I am a Jedi? Ohhh. Not yet. One thing remains: Vader. You must confront Vader. Then, only then, a Jedi will you be. And confront him you will. +Command station, this is ST 321. Code Clearance Blue. We're starting our approach. Deactivate the security shield. The security deflector shield will be deactivated when we have confirmation of your code transmission. Stand by... You are clear to proceed. We're starting our approach. Inform the commander that Lord Vader's shuttle has arrived. Yes, sir. +Not bad for a little furball. There's only one left. You stay here. We'll take care of this. I have decided that we shall stay here. +You can see here the Death Star orbiting the forest Moon of Endor. Although the weapon systems on this Death Star are not yet operational, the Death Star does have a strong defense mechanism. It is protected by an energy shield, which is generated from the nearby forest Moon of Endor. The shield must be deactivated if any attack is to be attempted. Once the shield is down, our cruisers will create a perimeter, while the fighters fly into the superstructure and attempt to knock out the main reactor. General Calrissian has volunteered to lead the fighter attack"; + public static string[] Places = + { + "Drall", + "Ylesia", + "Hoth", + "Almania", + "Duro", + "Selonia", + "Talus", + "Mon Calamari", + "Agamar", + "Borleias", + "Fondor", + "Kalarba", + "Antar Four", + "Bespin", + "Munto Codru", + "Carratos", + "J't'p'tan", + "Bakura", + "Pydyr", + "N'zoth", + "Dantooine", + "Abregado-rae", + "Lwhekk", + "Teyr", + "Dagobah", + "Firrerre", + "Aquaris", + "Etti IV", + "Carida", + "Wayland", + }; + public static string[] Names = + { + "Owen Lars", + "Dannik Jerriko", + "Emperor's Royal Guards", + "Tusken Raiders", + "Bollux", + "Sy Snootles", + "Hethrir", + "Tessek", + "Beru Lars", + "Moruth Doole", + "Momaw Nadon", + "Tenel Ka", + "Muftak", + "Gartogg", + "Princess Kneesaa", + "Wedge Antilles", + "Qwi Xux", + "Lady Valarian", + "Cindel Towani", + "Vima-Da-Boda", + "Nomi Sunrider", + "Admiral Ackbar", + "IG-88", + "Ulic Qel-Droma", + "Rillao", + "Brea Tonnika", + "General Crix Madine", + "Chewbacca", + "Dengar", + "Talon Karrde" + }; public static void Main(string[] args) { /* @@ -448,5 +527,20 @@ static void InitializeDemo() Console.ReadLine(); } + public static Demographic GetRandomPerson(string id, bool includeBio = false) + { + var person = new Demographic(); + person.RecordId = id; + person.FirstName = Names[rand.Next(Names.Length)]; + person.LastName = Places[rand.Next(Places.Length)]; + if (includeBio) + { + person.Bio = VeryLargeText; + } + return person; + } + } + + } diff --git a/RedcapApiDemo/SampleData.cs b/RedcapApiDemo/SampleData.cs new file mode 100644 index 0000000..a6bc46a --- /dev/null +++ b/RedcapApiDemo/SampleData.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace RedcapApiDemo +{ + class SampleData + { + } +} From c54db83bff433881a07d1887503b0c74bae1336a Mon Sep 17 00:00:00 2001 From: Michael Tran Date: Mon, 27 Jan 2020 12:46:22 -0500 Subject: [PATCH 6/6] Update README.md update to version 1.0.8 --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index eb76089..9ac3e18 100644 --- a/README.md +++ b/README.md @@ -74,21 +74,21 @@ __Install directly in Package Manager Console or Command Line Interface__ ```C# Package Manager -Install-Package RedcapAPI -Version 1.0.7 +Install-Package RedcapAPI -Version 1.0.8 ``` ```C# .NET CLI -dotnet add package RedcapAPI --version 1.0.7 +dotnet add package RedcapAPI --version 1.0.8 ``` ```C# Paket CLI -paket add RedcapAPI --version 1.0.7 +paket add RedcapAPI --version 1.0.8 ```