How to return error message in Rest API when return value is a Byte array? [duplicate] - azure

I have an Azure Function 2.x that reside on a static class that looks like this
[FunctionName("Register")]
public static async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "post")]HttpRequest req, ILogger log)
{
MyTypeClass defReturn = new MyTypeClass();
HttpStatusCode defCode = HttpStatusCode.BadRequest;
/*
* Logics that might or might not changes
* defReturn and defCode value
*/
return StatusCode((int) defCode, JsonConvert.SerializeObject(defReturn))
}
How can i achieve the return StatusCode((int) defCode, JsonConvert.SerializeObject(defReturn)) part ? is there any such method or equivalent in Azure Functions 2.x ?
in Azure Functions 1.x i can do the equivalent with req.CreateResponse(defCode, defReturn) where req is HttpRequestMessage , but i'm trying to stick with 2.x template/standard
Additional explanation : The said Code should return HTTP 400 Bad Request with the defReturn as it's response body to the client. But when i change the defCode to HttpStatusCode.Accepted, it should return HTTP 202 Accepted with the same response body. How can i achieve this ?
Additional explanation#2 : (If i remember correctly) in ASP.NET Core 1.x i can exactly do like that, returning IActionResult by calling a static method StatusCode not StatusCodes (which is a static class that contains HTTP codes constants
Thank you

Quite late reply, but I was stumbling into the same problem today, so maybe this is helpful for other searchers
Option 1: Default Codes
This is stated in detail on the blog Here
Some codes like 200 and 400 are predefined and can be used by
return new OkObjectResult("Your message"); // 200
return new BadRequestObjectResult("Your error message"); // 400
These functions are not available for every known Status Codes but some of the most frequent.
Option 2: Manual setting Code
If you need specific codes, that are not provided by default, you can use the base classes and create them yourself.
To achieve the Teapot Response for example, you can just use
using Microsoft.AspNetCore.Http;
var result = new ObjectResult("Your message");
result.StatusCode = StatusCodes.Status418ImATeapot;
return result;
In this example, the Statuscode is used from the StatusCodes class, but you can use enter other codes as well (usually, just stick to these codes)
Also, the ObjectResult class offers additional formatting options, if needed.

You can create a model class in which you can define two properties, i.e. one form your status code and one for you Json object and later on you can return the complete model. Code sample would be like below:
public static class QueueTriggerTableOutput
{
[FunctionName("QueueTriggerTableOutput")]
[return: Table("outTable", Connection = "MY_TABLE_STORAGE_ACCT_APP_SETTING")]
public static Person Run(
[QueueTrigger("myqueue-items", Connection = "MY_STORAGE_ACCT_APP_SETTING")]JObject order,
ILogger log)
{
return new Person() {
PartitionKey = "Orders",
RowKey = Guid.NewGuid().ToString(),
Name = order["Name"].ToString(),
MobileNumber = order["MobileNumber"].ToString() };
}
}
public class Person
{
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public string Name { get; set; }
public string MobileNumber { get; set; }
}
on the receiving front, you can catch both the property.
P.S.- you have to change the return type of your function.
Hope it helps.

Related

There is no implicit reference conversion from table to ITableEntity in Azure Function

I am writing my first Azure Function and Azure table code. I am getting issue when I write Get query function. I have the following code that would try to get all the jobs from the table.
public static class GetJobStatus
{
[FunctionName("GetJobStatus")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
[Table("JobTable")] CloudTable jobTable,
ILogger log)
{
log.LogInformation("Get job status.");
string jobId = req.Query["jobid"];
TableQuery<JobTable> query = new TableQuery<JobTable>();
var segment = await jobTable.ExecuteQuerySegmentedAsync(query, null);
var data = segment.Select(JobExtension.ToJob);
return new OkObjectResult("");
}
}
But, I get compile time errors on these statements:
TableQuery<JobTable> query = new TableQuery<JobTable>();
var segment = await jobTable.ExecuteQuerySegmentedAsync(query, null);
I am trying to paste the actual error messages that appear on hover:
and, get the following on the ExecuteQuerySegmentedAsync method
My JobTable inherits from ITableEntity (Azure.Data.Tables):
public class JobTable : ITableEntity
{
public string Id { get; set; }
public DateTime CreatedTime { get; set; }
public JobRequest Request { get; set; }
//ITableEntity Members
public virtual string PartitionKey { get; set; } = "Job";
public virtual string RowKey { get => Id; set => Id = value; }
public DateTimeOffset? Timestamp { get; set; }
public ETag ETag { get; set; }
}
I have the following nuget packages installed:
I was trying to implement from this article, but it uses older nuget packages, and I was getting trouble.
Update #1:
As per the suggestions from Gaurav Mantri, to be consistent, I have removed Azure.Data.Tables and started using Microsoft.WindowsAzure.Storage.Table. That fixed the compile time errors. But now I get the following runtime error:
Microsoft.Azure.WebJobs.Host: Error indexing method 'GetJobStatus'. Microsoft.Azure.WebJobs.Extensions.Tables: Can't bind Table to type 'Microsoft.WindowsAzure.Storage.Table.CloudTable'.
Update #2:
I couldn't make it work, so I reverted all my code and references to use Microsoft.Azure.Cosmos.Table as described in the article I was referncing. Everything works as expected now. But, I still would like to see how I can use the newer libraries. For the original issue that was receiving, it was solved by Gaurav's suggestion so I will accept the answer for now.
I believe you are running into this issue is because you are using two different SDKs - Azure.Data.Tables and Microsoft.WindowsAzure.Storage.Table.
Your JobTable entity implements ITableEntity from Azure.Data.Tables and you are using that with your CloudTable from Microsoft.WindowsAzure.Storage.Table.
Can you try by removing Azure.Data.Tables package and just use Microsoft.WindowsAzure.Storage.Table?

What is analog of Response.AddHeader("Refresh", "10") in ASP. NET MVC5

Would someone tell me if there is an analog of Response.AddHeader("Refresh", "10") in ASP. NET MVC5, please?
I have tried [OutputCache(NoStore = true, Location = OutputCacheLocation.Client, Duration = 10)] but it does not work.
[OutputCache] is for, well, caching the output of an action. The Duration param merely tells it how long to cache that output. Neither has anything to do with setting HTTP headers, and certainly will not make a page refresh automatically.
Reponse.AddHeader is still valid in MVC5; you just need to ensure that you have not started the response yet. Unless you're doing something off-the-wall, that's not difficult. If you're returning a ViewResult, for example, just call this first:
Response.AddHeader("Refresh", "10");
return View();
If you're directly writing to the response, then just ensure you add the header before you start doing that.
You can use it directly in your controller
public ActionResult MyAction()
{
Response.AddHeader("Refresh", "10");
return View();
}
Or you can make a custom action filter
public class RefreshAttribute : ActionFilterAttribute, IActionFilter
{
public string Duration { get; set; }
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var duration = 10;
Int32.TryParse(this.Duration, out duration);
filterContext.HttpContext.Response.AddHeader("Refresh", duration.ToString());
}
}
Usage
[Refresh(Duration = "10")]
public ActionResult MyAction()
{
return View();
}

How to create service in C# which will perform some operations asynchronously in scenario mentioned below?

I have WebApi Controller as mentioned below. This controller having Update method which will internally call service called CustomerDataService to Update Customer Records.Assume we have n customer records to update.
UpdateMethod in CustomerDataService will perform update and return the update response.
I have requirement to do some heavy processing asynchronously after the update response like manipulating data / managing the data cache. As this processing is time consuming not relevant to the consumer of this API as Update successfully happens So I have to perform this asynchronously. Can I do this with C# with the given scenario? Please suggest.
Note: I do not want to create any batch job to achieve this as I want to perform operation(s) which are user session specific.
Controller
public class CustomerController : ApiController
{
[HttpGet]
public string UpdateCustomer()
{
ICustomerService obj = new CustomerDataService();
return obj.UpdateCustomer(GetCustomerList());
}
private List<CustomerModel> GetCustomerList()
{
return new List<CustomerModel>()
{
new CustomerModel
{
CustomerId="1",
Name="John",
Category="P1"
},
new CustomerModel
{
CustomerId="2",
Name="Mike",
Category="P2"
}
//....n Records
};
}
}
Model
[Serializable]
[DataContract]
public class CustomerModel
{
[DataMember]
public string CustomerId { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string Category { get; set; }
}
Interface and CustomerDataService
public interface ICustomerService
{
string UpdateCustomer(List<CustomerModel> customerList);
}
public class CustomerDataService : ICustomerService
{
public string UpdateCustomer(List<CustomerModel> customerList)
{
//Do Data Processing - DB Call
//Return Confirmation Message
return "Data Updated Successfully!!!";
//Needs to perform some processing asynchronously i.e. Call ProcessResults()
}
private void ProcessResults()
{
//DO Processing
}
}
What you are looking for is using async/await in c#, see this article on Microsofts website: Asynchronous Programming with Async and Await. Here is another article with plenty of examples: C# Async, Await.
Once you understand how this works it will be very easy to change your code to take advantage of this pattern. Let us know if you have specific questions or run into problems.

Expose webjobs functions to dashboard without azure storage

In this question there's an example on how to use a webjob that can perform some background operations without interacting with azure table storage.
I tried to replicate the code in the answer but it's throwing the following error:
' 'Void ScheduleNotifications()' can't be invoked from Azure WebJobs SDK. Is it missing Azure WebJobs SDK attributes? '
In this link they have a similar error and in one of the answers it says that this was fixed in the 0.4.1-beta release. I'm running the 0.5.0-beta release and I'm experiencing the error.
Here's a copy of my code:
class Program
{
static void Main()
{
var config = new JobHostConfiguration(AzureStorageAccount.ConnectionString);
var host = new JobHost(config);
host.Call(typeof(Program).GetMethod("ScheduleNotifications"));
host.RunAndBlock();
}
[NoAutomaticTrigger]
public static void ScheduleNotifications()
{
//Do work
}
}
I want to know if I'm missing something or is this still a bug in the Webjobs SDK.
Update: Per Victor's answer, the Program class has to be public.
Working code:
public class Program
{
static void Main()
{
var config = new JobHostConfiguration(AzureStorageAccount.ConnectionString);
var host = new JobHost(config);
host.Call(typeof(Program).GetMethod("ScheduleNotifications"));
host.RunAndBlock();
}
[NoAutomaticTrigger]
public static void ScheduleNotifications()
{
//Do work
}
}
Unless you use a custom type locator, a function has to satisfy all conditions below:
it has to be public
it has to be static
it has to be non abstract
it has to be in a non abstract class
it has to be in a public class
Your function doesn't meet the last condition. If you make the class public it will work.
Also, if you use webjobs sdk 0.5.0-beta and you run a program with only the code in your example, you will see a message saying that no functions were found.
Came looking for an answer here, but didn't quite find it in the answer above, though everything he said is true. My problem was that I accidentally changed the inbound property names of a Azure web job so that they DIDN'T match the attributes of the object the function was supposed to catch. Duh!
For the concrete example:
my web job was listening for a queue message based on this class:
public class ProcessFileArgs
{
public ProcessFileArgs();
public string DealId { get; set; }
public ProcessFileType DmsFileType { get; set; }
public string Email { get; set; }
public string Filename { get; set; }
}
But my public static async class in the Functions.cs file contained this as a function definition, where the declared parameters didn't match the names within the queue message class for which it was waiting:
public static async Task LogAndLoadFile(
[QueueTrigger(Queues.SomeQueueName)] ProcessFileArgs processFileArgs,
string dealid,
string emailaddress,
string file,
[Blob("{fileFolder}/{Filename}", FileAccess.Read)] Stream input,
TextWriter log,
CancellationToken cancellationToke)
{
So if you run into this problem, check to make sure the parameter and attribute names match.

How would I change a ServiceStack response DTO

I'm working on an API where I'd like to be able to customize the response structure based on a parameter from the client. Response filters seem like a good place to do this in order to avoid doing so in each service or action. The problem is that while I have access to the response DTO returned by the action, and could change its properties, I can't find how or where to replace the object entirely.
Naively replacing the object in the response filter did not work, but this help illustrate what I'm trying to do:
public class ChangeResponseAttribute : ResponseFilterAttribute
{
public override void Execute(IHttpRequest req, IHttpResponse res, object responseDto)
{
var overrideText = req.QueryString["override"];
if (!String.IsNullOrEmpty(overrideText))
responseDto = new { Message = overrideText };
}
}
[ChangeResponse]
public class TodosService : Service
{
public object Get(Todos request)
{
return new object[0];
}
}
It looks like another option would be to write the custom response directly & end the request, but that would bypass any other processing left to do by ServiceStack.
Is there a better place to do this than a response filter? Or do I need to bite the bullet and return the optimal DTO in each action?
You can't change the Response DTO in a filter, but yes one option is to write the response in the filter itself (see this answer for an example of how to do this).
The other option is to use a ServiceRunner and override the OnAfterExecute() custom hook which does let you modify the response returned, e.g:
public class MyServiceRunner<T> : ServiceRunner<T>
{
public override object OnAfterExecute(
IRequestContext requestContext, object response)
{
// Called just after any Action is executed
var overrideText = req.Get<IHttpRequest>().QueryString["override"];
return !string.IsNullOrEmpty(overrideText)
? new { Message = overrideText } : null;
}
}
To get ServiceStack to use it you need to override the CreateServiceRunner method in your AppHost, e.g:
public override IServiceRunner<TRequest> CreateServiceRunner<TRequest>(
ActionContext actionContext)
{
return new MyServiceRunner<TRequest>(this, actionContext);
}

Resources