Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions examples/ResponseWithHeaders.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
```csharp
using System;
using System.IO;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Events;
using Twilio;
using Twilio.Rest.Api.V2010.Account;
using Twilio.Types;
using Twilio.Http;
using Twilio.Credential;

namespace TwilioTest {
class Program
{
static void Main(string[] args)
{
TwilioClient.Init(ACCOUNT_SID, AUTH_TOKEN);
}

public static void createWithHeaders()
{
var record = MessageResource.CreateWithHeaders(
from: new PhoneNumber("fromNumber"),
body: "Body",
to: new PhoneNumber("toNumber")
);
Console.WriteLine(record);
Console.WriteLine(record.Headers);
Console.WriteLine(record.Data.Sid);
}

public static void fetchWithHeaders()
{
var record = MessageResource.FetchWithHeaders(pathSid: "SM123");
Console.WriteLine(record);
Console.WriteLine(record.Headers);
Console.WriteLine(record.Data.Body);
}

public static void updateWithHeaders()
{
var record = MessageResource.UpdateWithHeaders(pathSid: "SM123", body: "");
Console.WriteLine(record);
Console.WriteLine(record.Headers);
Console.WriteLine(record.Data);
}

public static void deleteWithHeaders()
{
var record = MessageResource.DeleteWithHeaders(pathSid: "SM123");
Console.WriteLine(record);
Console.WriteLine(record.Headers);
Console.WriteLine(record.Data);
}
}
}
```
66 changes: 66 additions & 0 deletions src/Twilio/Base/ResourceSetResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System.Collections;
using System.Collections.Generic;
using System.Net;

#if NET35
using Headers = System.Net.WebHeaderCollection;
#else
using Headers = System.Net.Http.Headers.HttpResponseHeaders;
#endif

namespace Twilio.Base
{
/// <summary>
/// Wrapper class that contains both the resource set and HTTP response headers.
/// Implements IEnumerable to allow direct iteration over records.
/// </summary>
/// <typeparam name="T">The type of the resource</typeparam>
public class ResourceSetResponse<T> : IEnumerable<T> where T : Resource
{
/// <summary>
/// The resource set containing the records
/// </summary>
public ResourceSet<T> Records { get; }

/// <summary>
/// HTTP response headers from the initial request
/// </summary>
public Headers Headers { get; }

/// <summary>
/// HTTP status code from the initial request
/// </summary>
public HttpStatusCode StatusCode { get; }

/// <summary>
/// Create a new ResourceSetResponse
/// </summary>
/// <param name="records">The resource set containing records</param>
/// <param name="headers">HTTP response headers</param>
/// <param name="statusCode">HTTP status code</param>
public ResourceSetResponse(ResourceSet<T> records, Headers headers, HttpStatusCode statusCode)
{
Records = records;
Headers = headers;
StatusCode = statusCode;
}

/// <summary>
/// Get enumerator for iterating over resources
/// </summary>
/// <returns>IEnumerator of resources</returns>
public IEnumerator<T> GetEnumerator()
{
return Records.GetEnumerator();
}

/// <summary>
/// Get enumerator for iterating over resources
/// </summary>
/// <returns>IEnumerator of resources</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
45 changes: 45 additions & 0 deletions src/Twilio/Base/TwilioResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System.Net;

#if NET35
using Headers = System.Net.WebHeaderCollection;
#else
using Headers = System.Net.Http.Headers.HttpResponseHeaders;
#endif

namespace Twilio.Base
{
/// <summary>
/// Wrapper class that contains both the resource and HTTP response headers
/// </summary>
/// <typeparam name="T">The type of the resource</typeparam>
public class TwilioResponse<T>
{
/// <summary>
/// The resource data
/// </summary>
public T Data { get; }

/// <summary>
/// HTTP response headers
/// </summary>
public Headers Headers { get; }

/// <summary>
/// HTTP status code
/// </summary>
public HttpStatusCode StatusCode { get; }

/// <summary>
/// Create a new TwilioResponse
/// </summary>
/// <param name="data">The resource data</param>
/// <param name="headers">HTTP response headers</param>
/// <param name="statusCode">HTTP status code</param>
public TwilioResponse(T data, Headers headers, HttpStatusCode statusCode)
{
Data = data;
Headers = headers;
StatusCode = statusCode;
}
}
}
176 changes: 176 additions & 0 deletions test/Twilio.Test/Base/ResourceSetResponseTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using NUnit.Framework;
using Twilio.Base;

#if !NET35
using System.Net.Http;
#endif

namespace Twilio.Tests.Base
{
[TestFixture]
public class ResourceSetResponseTest
{
// Mock resource class for testing
private class MockResource : Resource
{
public string Id { get; set; }
public string Name { get; set; }
}

// Mock ReadOptions for testing
private class MockReadOptions : ReadOptions<MockResource>
{
}

#if !NET35
private ResourceSet<MockResource> CreateMockResourceSet(List<MockResource> records)
{
// Create a JSON string that Page<T>.FromJson can parse
var json = CreatePageJson(records);
var page = Page<MockResource>.FromJson("records", json);
var options = new MockReadOptions();
return new ResourceSet<MockResource>(page, options, null);
}

private string CreatePageJson(List<MockResource> records)
{
var recordsJson = string.Join(",", records.Select(r =>
$"{{\"Id\":\"{r.Id}\",\"Name\":\"{r.Name}\"}}"));
return $"{{\"records\":[{recordsJson}],\"page_size\":{records.Count},\"uri\":\"/test\"}}";
}

[Test]
public void TestResourceSetResponseProperties()
{
var records = new List<MockResource>
{
new MockResource { Id = "1", Name = "First" },
new MockResource { Id = "2", Name = "Second" }
};
var resourceSet = CreateMockResourceSet(records);
var headers = new HttpResponseMessage().Headers;
var statusCode = HttpStatusCode.OK;

var response = new ResourceSetResponse<MockResource>(resourceSet, headers, statusCode);

Assert.AreEqual(resourceSet, response.Records);
Assert.AreEqual(headers, response.Headers);
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}

[Test]
public void TestResourceSetResponseEnumeration()
{
var records = new List<MockResource>
{
new MockResource { Id = "1", Name = "First" },
new MockResource { Id = "2", Name = "Second" },
new MockResource { Id = "3", Name = "Third" }
};
var resourceSet = CreateMockResourceSet(records);
resourceSet.AutoPaging = false;
var headers = new HttpResponseMessage().Headers;
var statusCode = HttpStatusCode.OK;

var response = new ResourceSetResponse<MockResource>(resourceSet, headers, statusCode);

// Test enumeration through the response
var enumeratedRecords = response.ToList();
Assert.AreEqual(3, enumeratedRecords.Count);
Assert.AreEqual("1", enumeratedRecords[0].Id);
Assert.AreEqual("2", enumeratedRecords[1].Id);
Assert.AreEqual("3", enumeratedRecords[2].Id);
}

[Test]
public void TestResourceSetResponseWithEmptySet()
{
var records = new List<MockResource>();
var resourceSet = CreateMockResourceSet(records);
resourceSet.AutoPaging = false;
var headers = new HttpResponseMessage().Headers;
var statusCode = HttpStatusCode.OK;

var response = new ResourceSetResponse<MockResource>(resourceSet, headers, statusCode);

var enumeratedRecords = response.ToList();
Assert.AreEqual(0, enumeratedRecords.Count);
}

[Test]
public void TestResourceSetResponseWithDifferentStatusCodes()
{
var records = new List<MockResource>
{
new MockResource { Id = "1", Name = "Test" }
};
var resourceSet = CreateMockResourceSet(records);
var headers = new HttpResponseMessage().Headers;

var okResponse = new ResourceSetResponse<MockResource>(resourceSet, headers, HttpStatusCode.OK);
Assert.AreEqual(HttpStatusCode.OK, okResponse.StatusCode);

var partialResponse = new ResourceSetResponse<MockResource>(resourceSet, headers, HttpStatusCode.PartialContent);
Assert.AreEqual(HttpStatusCode.PartialContent, partialResponse.StatusCode);
}

[Test]
public void TestResourceSetResponseForeachEnumeration()
{
var records = new List<MockResource>
{
new MockResource { Id = "A", Name = "Alpha" },
new MockResource { Id = "B", Name = "Beta" }
};
var resourceSet = CreateMockResourceSet(records);
resourceSet.AutoPaging = false;
var headers = new HttpResponseMessage().Headers;
var statusCode = HttpStatusCode.OK;

var response = new ResourceSetResponse<MockResource>(resourceSet, headers, statusCode);

// Test foreach enumeration
var ids = new List<string>();
foreach (var record in response)
{
ids.Add(record.Id);
}

Assert.AreEqual(2, ids.Count);
Assert.Contains("A", ids);
Assert.Contains("B", ids);
}

[Test]
public void TestResourceSetResponseLinqOperations()
{
var records = new List<MockResource>
{
new MockResource { Id = "1", Name = "Apple" },
new MockResource { Id = "2", Name = "Banana" },
new MockResource { Id = "3", Name = "Cherry" }
};
var resourceSet = CreateMockResourceSet(records);
resourceSet.AutoPaging = false;
var headers = new HttpResponseMessage().Headers;
var statusCode = HttpStatusCode.OK;

var response = new ResourceSetResponse<MockResource>(resourceSet, headers, statusCode);

// Test LINQ operations
var firstRecord = response.First();
Assert.AreEqual("1", firstRecord.Id);

var count = response.Count();
Assert.AreEqual(3, count);

var filtered = response.Where(r => r.Name.StartsWith("B")).ToList();
Assert.AreEqual(1, filtered.Count);
Assert.AreEqual("Banana", filtered[0].Name);
}
#endif
}
}
Loading
Loading