I have been using the following piece of code for a while now and it has been working perfectly. However, today I got the following error:
TypeError: Member "add" not found or not visible after argument-dependent lookup in struct >Chainlink.Request memory.
I tried switching my Solidity version to 0.6.6 and consequently the Chainlink version to v0.6 and it seems to work perfectly with the older version.
Does anybody have a suggestion as to what might be going wrong?
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;
import "#chainlink/contracts/src/v0.8/ChainlinkClient.sol";
contract APIConsumer is ChainlinkClient {
uint256 public volume;
address private oracle;
bytes32 private jobId;
uint256 private fee;
address public _link = 0xa36085F69e2889c224210F603D836748e7dC0088;
constructor() {
if (_link == address(0)) {
setPublicChainlinkToken();
} else {
setChainlinkToken(_link);
}
oracle = 0x56dd6586DB0D08c6Ce7B2f2805af28616E082455;
jobId = "b6602d14e4734c49a5e1ce19d45a4632";
fee = 0.1 * 10 ** 18; // 0.1 LINK
}
function requestVolumeData() public returns (bytes32 requestId)
{
Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);
// Set the URL to perform the GET request on
request.add("get", "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD");
request.add("path", "RAW.ETH.USD.VOLUME24HOUR");
int timesAmount = 10**18;
request.addInt("times", timesAmount);
// Sends the request
return sendChainlinkRequestTo(oracle, request, fee);
}
function fulfill(bytes32 _requestId, uint256 _volume) public recordChainlinkFulfillment(_requestId)
{
volume = _volume;
}
}
Yes! Good question.
This is an update to newer contracts.
Add this line:
contract APIConsumer is ChainlinkClient {
using Chainlink for Chainlink.Request; // This is the new line
Related
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.
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?
I would like to allow callers to pass an external routing slip, e.g. by posting:
POST http://localhost:8080/transform?routing-slip=capitalize&routing-slip=lowercase
Content-Type: text/plain
camelCase
It should be possible to use the given routing-slip array as external routing slip from a pojo:
#Bean
public IntegrationFlow transformerChain(RoutingSlipRouteStrategy routeStrategy) {
return IntegrationFlows.from(
Http.inboundGateway("/transform")
.headerExpression("routingSlipParam",
"#requestParams['routing-slip']")
.requestPayloadType(String.class))
.enrichHeaders(spec -> spec.header(
IntegrationMessageHeaderAccessor.ROUTING_SLIP,
new RoutingSlipHeaderValueMessageProcessor(
"#routePojo.get(request, reply)")
)
)
.logAndReply();
}
The pojo can access the routingSlipParam header and you would think it can then hold the slip as internal state, or at least that is what TestRoutingSlipRoutePojo lead me to believe, so I built this (with a slight doubt, given that there is only one instance of the pojo):
public class ExternalRoutingSlipRoutePojo {
private List<String> routingSlip;
private int i = 0;
public String get(Message<?> requestMessage, Object reply) {
if (routingSlip == null) {
routingSlip = (LinkedList)requestMessage.getHeaders()
.get("routingSlipParam");
}
try {
return this.routingSlip.get(i++);
} catch (Exception e) {
return null;
}
}
}
It turns out that this only works exactly once, which is not surprising after all - the index is incremented for every incoming message and the routing slip is never updated.
So I thought, sure, I have to hold the internal status for all incoming messages and came up with this RouteStrategy:
public class ExternalRoutingSlipRouteStrategy implements RoutingSlipRouteStrategy {
private Map<UUID, LinkedList<String>> routingSlips = new WeakHashMap<>();
private static final LinkedList EMPTY_ROUTINGSLIP = new LinkedList<>();
#Override
public Object getNextPath(Message<?> requestMessage,Object reply) {
MessageHeaders headers = requestMessage.getHeaders();
UUID id = headers.getId();
if (!routingSlips.containsKey(id)) {
#SuppressWarnings("unchecked")
List<String> routingSlipParam =
headers.get("routingSlipParam", List.class);
if (routingSlipParam != null) {
routingSlips.put(id,
new LinkedList<>(routingSlipParam));
}
}
LinkedList<String> routingSlip = routingSlips.getOrDefault(id,
EMPTY_ROUTINGSLIP);
String nextPath = routingSlip.poll();
if (nextPath == null) {
routingSlips.remove(id);
}
return nextPath;
}
}
That does not work either because the strategy is not only called for the incoming message but also for all the new messages which are created by the dynamic routing, which of course have different IDs.
But it is only called twice for the original message, so the routing slip never gets exhausted and the application runs in an endless loop.
How can I make spring-integration use an external routing slip?
UPDATE:
As suggested by Gary Russel, neither the external routing slip index nor the external routing slip itself should be stored in the Spring bean, rather one can use message headers to maintain them separately for each request:
Http.inboundGateway("/transform")
.headerExpression("routingSlipParam",
"#requestParams['routing-slip']")
.requestPayloadType(String.class))
.enrichHeaders(spec -> spec
.headerFunction("counter",h -> new AtomicInteger())
.header(IntegrationMessageHeaderAccessor.ROUTING_SLIP,
new RoutingSlipHeaderValueMessageProcessor(externalRouteStrategy)
)
)
The externalRouteStrategy is an instance of the following class:
public class ExternalRoutingSlipRouteStrategy implements
RoutingSlipRouteStrategy {
#Override
public Object getNextPath(Message<?> requestMessage, Object reply) {
List<String> routingSlip = (List<String>)
requestMessage.getHeaders().get("routingSlipParam");
int routingSlipIndex = requestMessage.getHeaders()
.get("counter", AtomicInteger.class)
.getAndIncrement();
String routingSlipEntry;
if (routingSlip != null
&& routingSlipIndex < routingSlip.size()) {
routingSlipEntry = routingSlip.get(routingSlipIndex);
} else {
routingSlipEntry = null;
}
return routingSlipEntry;
}
}
For reference, I have published the example in Github.
Go back to your first version and store i in a message header (AtomicInteger) in the header enricher.
.headerExpression("counter", "new java.util.concurrent.atomic.AtomicInteger()")
then
int i = requestMessage.getHeaders().get("counter", AtomicInteger.class).getAndIncrement();
I have created a custom observer "sales_order_save_before". The event is working fine but when I tried to log the post data it always blank array. Although I can see the post data in console.I have used following code.
namespace Test\Check\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Event\Observer;
class SalesOrderBeforeSaveObserver implements ObserverInterface
{
public function __construct(\Magento\Framework\App\RequestInterface $request)
{
$this->_request = $request;
}
public function execute(\Magento\Framework\Event\Observer $observer)
{
$order = $observer->getEvent()->getOrder();
if ($order->getPayment()->getMethodInstance()->getCode() == 'test')
{
$data=$this->_request;
print_r($data);die; /*Not working */
}
return $this;
} }
I'm trying to write a target for NLog to send messages out to connected clients using SignalR.
Here's what I have now. What I'm wondering is should I be using resolving the ConnectionManager like this -or- somehow obtain a reference to the hub (SignalrTargetHub) and call a SendMessage method on it?
Are there performance ramifications for either?
[Target("Signalr")]
public class SignalrTarget:TargetWithLayout
{
public SignalR.IConnectionManager ConnectionManager { get; set; }
public SignalrTarget()
{
ConnectionManager = AspNetHost.DependencyResolver.Resolve<IConnectionManager>();
}
protected override void Write(NLog.LogEventInfo logEvent)
{
dynamic clients = GetClients();
var logEventObject = new
{
Message = this.Layout.Render(logEvent),
Level = logEvent.Level.Name,
TimeStamp = logEvent.TimeStamp.ToString("yyyy-MM-dd HH:mm:ss.fff")
};
clients.onLoggedEvent(logEventObject);
}
private dynamic GetClients()
{
return ConnectionManager.GetClients<SignalrTargetHub>();
}
}
I ended up with the basic the same basic structure that I started with. Just a few tweaks to get the information I needed.
Added exception details.
Html encoded the final message.
[Target("Signalr")]
public class SignalrTarget:TargetWithLayout
{
protected override void Write(NLog.LogEventInfo logEvent)
{
var sb = new System.Text.StringBuilder();
sb.Append(this.Layout.Render(logEvent));
if (logEvent.Exception != null)
sb.AppendLine().Append(logEvent.Exception.ToString());
var message = HttpUtility.HtmlEncode(sb.ToString());
var logEventObject = new
{
Message = message,
Logger = logEvent.LoggerName,
Level = logEvent.Level.Name,
TimeStamp = logEvent.TimeStamp.ToString("HH:mm:ss.fff")
};
GetClients().onLoggedEvent(logEventObject);
}
private dynamic GetClients()
{
return AspNetHost.DependencyResolver.Resolve<IConnectionManager>().GetClients<SignalrTargetHub>();
}
}
In my simple testing it's working well. Still remains to be seen if this adds any significant load when under stress.