I understood that setTokenURI function isn't in use anymore. How can I change the token URI of the NFT token I want to create?
for now my function createCollectible inside the smart contract looks like this:
function createCollectible(string memory tokenURI)
public
returns (uint256)
{
uint256 newItemId = tokenId;
_safeMint(msg.sender, newItemId);
_setTokenURI(newItemId, tokenURI);
tokenId = tokenId + 1;
return newItemId;
}
_setTokenURI is still used but it is moved to the ERC721URIStorage. Here is the openzeppelin link
When you create your contract, you should inherit:
contract NFT is ERC721URIStorage { }
Since calling it an expensive operation, team wants you to use tokenUri function in ERC721:
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
string memory baseURI = _baseURI();
return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
}
this is _baseUri() which is inherited from ERC721. It is virtual so that you can override it inside ERC721URIStorage and change it from "" to anything you want.
function _baseURI() internal view virtual returns (string memory) {
return "";
}
this time you need to inherit from ERC721
contract NFT is ERC721{
function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
require(_exists(tokenId), "...");
_tokenURIs[tokenId] = _tokenURI;
}
}
They both have different use cases: Discussed Here
Related
My code:
public string GetUserId(IRequest request) {
var token = request.QueryString.Get("token");
// what is it? request.User.Identity.Name;
if (string.IsNullOrWhiteSpace(token)) {
return token;
}
else {
return JsonConvert.SerializeObject(new UserAbility().GetUserByToken(token));
}
}
I need to map the connection with the user using a different identifier.
So i want to get the custom token from the QueryString in this method, but GetUserId doesn't trigger in every reqeust.
And i always get the request.User.Identity.Name is string empty?
This article explains what you need to do.
http://www.asp.net/signalr/overview/guide-to-the-api/mapping-users-to-connections#IUserIdProvider
I'm writing a Nancy endpoint and I want to do something that I think should be really simple. I want to support returning the content in either json or xml but when html or any other type is requested to return a 406 Not supported. I can easily force either XML or JSON only, and I guess I could do and if (accept is html) return 406 but I would assume that there is some support for this in the content Negotiation support.
Can anybody shed any light?
Implement your own IResponseProcessor, Nancy will pick it up and hook in the engine.
public sealed class NoJsonOrXmlProcessor : IResponseProcessor
{
public ProcessorMatch CanProcess(MediaRange requestedMediaRange, dynamic model, NancyContext context)
{
if (requestedMediaRange.Matches("application/json") || requestedMediaRange.Matches("aaplication/xml"))
{
//pass on, so the real processors can handle
return new ProcessorMatch{ModelResult = MatchResult.NoMatch, RequestedContentTypeResult = MatchResult.NoMatch};
}
return new ProcessorMatch{ModelResult = MatchResult.ExactMatch, RequestedContentTypeResult = MatchResult.ExactMatch};
}
public Response Process(MediaRange requestedMediaRange, dynamic model, NancyContext context)
{
return new Response{StatusCode = HttpStatusCode.NotAcceptable};
}
public IEnumerable<Tuple<string, MediaRange>> ExtensionMappings { get; private set; }
}
We avoided the use of ResponseProcessor for the whole reason that the request was still being run all the way through our authentication layer, domain layer, etc. We wanted a way to quickly kill the request as soon as possible.
What we ended up doing was performing the check inside our own Boostrapper
public class Boostrapper : DefaultNancyBootstrapper
{
protected override void RequestStartup(TinyIoCContainer requestContainer, IPipelines pipelines, NancyContext context)
{
base.RequestStartup(requestContainer, pipelines, context);
pipelines.BeforeRequest += nancyContext =>
{
RequestHeaders headers = nancyContext.Request.Headers
if (!IsAcceptHeadersAllowed(headers.Accept))
{
return new Response() {StatusCode = HttpStatusCode.NotAcceptable};
}
return null;
}
}
private bool IsAcceptHeadersAllowed(IEnumerable<Tuple<string, decimal>> acceptTypes)
{
return acceptTypes.Any(tuple =>
{
var accept = new MediaRange(tuple.Item1);
return accept.Matches("application/json") || accept.Matches("application/xml");
});
}
}
We have been transferring our services and MVC4 website to the cloud, overall this process went fine.
Except for caching, since we have moved to Azure it would also be wise to use some kind of caching which azure provides. We choose for co-located / dedicated caching role which has the advantage that the cache is used over all the instances.
Setting up the caching worked fine, I've got a named caching client which I only initialize when its required. It is set up in a inherited layer of the controllers. As soon as one of the functions is called, it checks if the connection to the data-cache is still there or its created. This all seems to work fine, but I'm building a module do retrieve prices. And multiple ajax inserts (views which get inserted into the page with use of javascript) use these functions, some of them are called at the same time, by multiple ajax views. Some of these views then return either a 404 or 500 error, and I cant explain where these are coming from except a non working caching, or something alike.
Can someone help me with a good implementation of the named caching (co-located or dedicated), since all I can find is many examples illustrating the initializing of the DataCacheFactory, but not of the data insertion and retrieval.
Below is the code as I have it now, I've tried more ways with use of locking etc but this one so far worked best.
private static object magicStick = new object();
private static DataCacheFactory dcf = null;
private static DataCache priceCache = null;
protected void CreateCacheFactory()
{
dcf = new DataCacheFactory();
}
protected void CreatePricesCache()
{
if (dcf == null)
{
CreateCacheFactory();
}
priceCache = dcf.GetCache("Prices");
}
protected PriceData GetPrices(int productID)
{
if (priceCache == null)
{
CreatePricesCache();
}
string cacheKey = "something";
lock (magicStick)
{
PriceData datas = priceCache.Get(cacheKey) as PriceData;
if (datas == null)
{
lock (magicStick)
{
Services svc = new Services();
PriceData pData = svc.PriceService.GetPrices(productID);
if (pData != null && pData.Offers != null && pData.Offers.Count() > 0)
{
datas = pData;
datas.Offers = datas.Offers.OrderBy(pr => (pr.BasePrice + pr.ShippingCosts)).ToArray();
priceCache.Add(cacheKey, datas, new TimeSpan(0, cachingTimePricesKK, 0));
}
}
}
return datas;
}
}
As soon as I get to a page where there are pricelists and the function above is called multiple times with the same arguments, there is a 5-10% chance that it returns an error rather then returning the results. Can anybody help me, im totally stuck with this for a week now and its eating me up inside.
First I'd move your cache and cacheFactory instantiation out of your getPrices method. Also, evaluate your need for the lock - this may be causing timeouts. Another VERY important observation - you are using a constant cache key and saving/retrieving data for every productId with the same cache key. You should be using a cache key like: var cacheKey = string.format("priceDatabyProductId-{0}", productId);. You need to set some breakpoints and examine exactly what you are caching and retrieving from the cache. The code as written will save the first productId to the cache and then keep returning that data regardless of the productId.
Here is a full working example we use in production using the "default" named cache in dedicated cache roles:
public static class MyCache
{
private static DataCacheFactory _cacheFactory = null;
private static DataCache ACache
{
get
{
if (_cacheFactory == null)
{
try
{
_retryPolicy.ExecuteAction(() => { _cacheFactory = new DataCacheFactory(); });
return _cacheFactory == null ? null : _cacheFactory.GetDefaultCache();
}
catch (Exception ex)
{
ErrorSignal.FromCurrentContext().Raise(ex);
return null;
}
}
return _cacheFactory.GetDefaultCache();
}
}
public static void FlushCache()
{
ACache.Clear();
}
// Define your retry strategy: retry 3 times, 1 second apart.
private static readonly FixedInterval _retryStrategy = new FixedInterval(3, TimeSpan.FromSeconds(1));
// Define your retry policy using the retry strategy and the Windows Azure storage
// transient fault detection strategy.
private static RetryPolicy _retryPolicy = new RetryPolicy<StorageTransientErrorDetectionStrategy>(_retryStrategy);
// Private constructor to prevent instantiation
// and force consumers to use the Instance property
static MyCache()
{ }
/// <summary>
/// Add an item to the cache with a key and set a absolute expiration on it
/// </summary>
public static void Add(string key, object value, int minutes = 90)
{
try
{
_retryPolicy.ExecuteAction(() => { ACache.Put(key, value, TimeSpan.FromMinutes(minutes)); });
}
catch (Exception ex)
{
ErrorSignal.FromCurrentContext().Raise(ex);
}
}
/// <summary>
/// Add the object with the specified key to the cache if it does not exist, or replace the object if it does exist and set a absolute expiration on it
/// only valid for Azure caching
/// </summary>
public static void Put(string key, object value, int minutes = 90)
{
try
{
_retryPolicy.ExecuteAction(() => { ACache.Put(key, value, TimeSpan.FromMinutes(minutes)); });
}
catch (Exception ex)
{
ErrorSignal.FromCurrentContext().Raise(ex);
}
}
/// <summary>
/// Get a strongly typed item out of cache
/// </summary>
public static T Get<T>(string key) where T : class
{
try
{
object value = null;
_retryPolicy.ExecuteAction(() => { value = ACache.Get(key); });
if (value != null) return (T) value;
return null;
}
catch (DataCacheException ex)
{
ErrorSignal.FromCurrentContext().Raise(ex);
return null;
}
catch (Exception ex)
{
ErrorSignal.FromCurrentContext().Raise(ex);
return null;
}
}
/// <summary>
/// Microsoft's suggested method for cleaning up resources such as this in a static class
/// to ensure connections and other consumed resources are returned to the resource pool
/// as quickly as possible.
/// </summary>
public static void Uninitialize()
{
if (_cacheFactory == null) return;
_cacheFactory.Dispose();
_cacheFactory = null;
}
}
Note: this is also using the Transient Fault Handling block from the Enterprise Library for transient exception fault handling.
I'm trying to use WebRequest.RegisterPrefix to register a decorator IWebRequestCreate implementation with the intention being to add "debug" scenarios (like emulating different connectivity scenarios).
I'm using the Mango beta 2 SDK and the RegisterPrefix method always returns true when used with "http://" as a prefix (or "http" for that matter), but the registered IWebRequestCreate instance is not being used.
I can see from the documentation that it should return false for duplicates, but it doesn't seem to be functioning as documented.
Is there any other way of achieving what I'm after in a way that is transparent to consumers?
I'm using WebRequest.RegisterPrefix for unit testing, registering an IWebRequestCreate implementation for a prefix of test://, and this does work.
I found that after registering an IWebRequestCreate for http://, calling WebRequest.Create with an http:// uri would return a request created from the registered IWebRequestCreate, but calling WebRequest.CreateHttp would still return an HttpWebRequest.
The following code should verify this, and I'm using the Mango Beta 2 SDK (6-29-11):
public partial class MainPage : PhoneApplicationPage
{
public class FakeRequest : WebRequest
{
private Uri _uri;
public FakeRequest(Uri uri)
{
_uri = uri;
}
public override Uri RequestUri { get { return _uri; } }
}
public class FakeRequestFactory : IWebRequestCreate
{
public WebRequest Create(Uri uri)
{
return new FakeRequest(uri);
}
}
// Constructor
public MainPage()
{
InitializeComponent();
// returns System.Net.Browser.ClientHttpWebRequest
var request1 = WebRequest.Create("http://www.foo.com");
// returns System.Net.Browser.ClientHttpWebRequest
var request2 = WebRequest.CreateHttp("http://www.foo.com");
// returns true
bool result1 = WebRequest.RegisterPrefix("http://", new FakeRequestFactory());
// returns FakeRequest
var request3 = WebRequest.Create("http://www.foo.com");
// returns System.Net.Browser.ClientHttpWebRequest
var request4 = WebRequest.CreateHttp("http://www.foo.com");
// returns false
bool result2 = WebRequest.RegisterPrefix("http://", new FakeRequestFactory());
// returns false, as per the note in the documention
bool result3 = HttpWebRequest.RegisterPrefix("http://", new FakeRequestFactory());
}
}
Hey I know this question is 2 years old but I came across the same problem. I think you'll find that WebRequest.RegisterPrefix() does return false if you try to register http: (notice the single colon, no forward slashes). If I ever find a workaround, I'll try to remember to update this post.
EDIT
In my particular case I wanted to throw out System.Net.FtpWebRequest and roll my own FTP client implementation (because the framework's implementation sucks).
In order to do that, I used reflection (and a bunch of late binding tricks) to get the arraylist of registered prefix and remove the ones that are linked to the internal System.Net.FtpWebRequestCreator class.
I'm not sure if all of these APIs are available for windows phone, but here's what I did:
Type webRequest = typeof(System.Net.WebRequest);
Assembly system = Assembly.GetAssembly(webRequest);
Type ftpWebRequestCreator = system.GetType("System.Net.FtpWebRequestCreator");
ArrayList prefixList = (ArrayList)webRequest.GetProperty("PrefixList", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null, null);
IEnumerator enumerator = prefixList.GetEnumerator();
while (enumerator != null && enumerator.MoveNext()) {
if (object.ReferenceEquals(enumerator.Current.Creator.GetType(), ftpWebRequestCreator)) {
prefixList.Remove(enumerator.Current);
if (System.Net.WebRequest.RegisterPrefix(enumerator.Current.Prefix, new CustomWebRequestCreator())) {
enumerator = null;
} else {
enumerator = prefixList.GetEnumerator();
}
}
}
// Now I can use Create() on the base class
System.Net.WebRequest myCustomWebRequest = System.Net.WebRequest.Create("ftp://example.com/public");
This works by finding all prefixes that are registered with FtpWebRequestCreator and replacing them with my own creator. It should be fairly straightforward to adapt this for http(s).
The phone only has a client stack so RegisterPrefix has no effect on the phone.
I'm currently developing my own AuthorizationManager, it looks something like that:
public class MyAuthorizationManager : ServiceAuthorizationManager
{
static bool initialize = false;
public override bool CheckAccess(OperationContext operationContext)
{
ServiceSecurityContext context = ServiceSecurityContext.Current;
string[] roles = Roles.GetRolesForUser(operationContext.ServiceSecurityContext.PrimaryIdentity.Name);
return roles.Count() > 0;
}
public override bool CheckAccess(OperationContext operationContext, ref System.ServiceModel.Channels.Message message)
{
MessageBuffer buffer = operationContext.RequestContext.RequestMessage.CreateBufferedCopy(int.MaxValue);
message = buffer.CreateMessage();
Console.WriteLine(message);
return base.CheckAccess(operationContext, ref message);
}
}
I would like to perform authorization check based on a service contract parameter, in example, if contract looks like:
[ServiceContract]
public interface IServerContract
{
[OperationContract]
[ServiceKnownType(typeof(ChildTypeOne))]
[ServiceKnownType(typeof(ChildTypeTwo))]
string SecuredMessage(ParentType incoming);
}
My goal is authorizing depending on type, in example, authorizing if incoming date is ChildTypeOne and deniying in case it was ChildTypeTwo.
I've checked "Message" and it looks like:
It must be decrypted
Seems to be highly dependent on binding
Is there any easy way to simply get parameter type?
Ok, i've figured out how to perform that. Anyway, if you know any better way to do so, let me know:
Here is the AuthorizationManager i'm using:
public class MyAuthorizationManager : ServiceAuthorizationManager
{
static bool initialize = false;
public override bool CheckAccess(OperationContext operationContext, ref System.ServiceModel.Channels.Message message)
{
bool returnedValue = base.CheckAccess(operationContext, ref message);
// messags in WCF are always read-once
// we create one copy to work with, and one copy to return back to the plumbing
MessageBuffer buffer = operationContext.RequestContext.RequestMessage.CreateBufferedCopy(int.MaxValue);
message = buffer.CreateMessage();
// get the username vale using XPath
XPathNavigator nav = buffer.CreateNavigator();
StandardNamespaceManager nsm = new StandardNamespaceManager(nav.NameTable);
nav = nav.SelectSingleNode("//#i:type",nsm);
returnedValue &= (nav.ToString() == "a:"+typeof(ChildTypeOne).Name);
return returnedValue;
}
public class StandardNamespaceManager : XmlNamespaceManager
{
public StandardNamespaceManager(XmlNameTable nameTable)
: base(nameTable)
{
this.AddNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/");
this.AddNamespace("s11", "http://schemas.xmlsoap.org/soap/envelope/");
this.AddNamespace("s12", "http://www.w3.org/2003/05/soap-envelope");
this.AddNamespace("wsaAugust2004", "http://schemas.xmlsoap.org/ws/2004/08/addressing");
this.AddNamespace("wsa10", "http://www.w3.org/2005/08/addressing");
this.AddNamespace("i", "http://www.w3.org/2001/XMLSchema-instance");
}
}
}
Previous AuthorizationManager will work rejecting "ChildTypeTwo". You can use a RoleProvider in order to get role based on type.