RazorEngineCore - How to use extension methods - razor

I am working with RazorEngineCore and am coming across an issue where extension methods are not being identified properly. In my sample below, I am trying to use LINQ's single, and the error is:
'System.Collections.Generic.List' does not contain a definition for 'First'
I've added the required assemblies using AddAssemblyReferenceByName() and assume it would load correctly. Yet I'm still getting the error.
Sample code:
class Program
{
static string Content = #"
Hello #Model.Name
First item: #Model.Items.First();
#foreach(var item in #Model.Items)
{
<div>- #item</div>
}
<div data-name=""#Model.Name""></div>
<area>
#{ RecursionTest(3); }
</area>
#{
void RecursionTest(int level){
if (level <= 0)
{
return;
}
<div>LEVEL: #level</div>
#{ RecursionTest(level - 1); }
}
}";
static void Main(string[] args)
{
IRazorEngine razorEngine = new RazorEngine();
IRazorEngineCompiledTemplate template = razorEngine.Compile(Content,
builder =>
{
builder.AddAssemblyReferenceByName("System.Collections");
builder.AddAssemblyReferenceByName("System.Linq");
});
string result = template.Run(new
{
Name = "Alexander",
Items = new List<string>()
{
"item 1",
"item 2"
}
});
Console.WriteLine(result);
Console.ReadKey();
}
}
Edit: When I call the extension method fully qualified, it works. ie, calling System.Linq.First(myList) instead of myList.Single().

Related

Trouble Serializing JSON data for an object array from JS for Unity

I am trying to send data from JS to C# in Unity in a WebGL project, but I am not as familiar with javascript and JSON.
In the JS code, I am serializing an array of objects from js with Json.Stringify, and that is sent to Unity as a string. This is what comes through to Unity...
[
[],[],[],[],
[
{
"damage": 0,
"opaque": false,
"safe": false
}
],
[
{
"damage": 0,
"opaque": false,
"safe": false
}
]
]
I did not write the js code, so I am not sure what exactly to post. If it seems like my Unity code is okay, I will try to see what I can share from js.
I am not sure why there are empty brackets above. I wonder if unity is getting stuck trying
to serialize those empty sets.
I made two Serializable classes in Unity for the incoming objects.
[System.Serializable]
public class minimap
{
public int damage;
public bool opaque;
public bool safe;
}
[System.Serializable]
public class minimaps
{
public minimap[] minimapArray;
}
On a gameObject, I placed a script that is called from JS. The "Json convert completed" works, but the minimap loop does not. The array seems to have something in it, but not what I was hoping for unless I am not accessing it properly.
public class GameController : MonoBehaviour
{
public JsonDeserialize(string minimap)
{
minimaps minimaps = JsonUtility.FromJson<minimaps>(minimap);
if(minimaps != null) _debugText.text += "JSON convert completed";
foreach (minimap mm in minimaps.minimapArray)
{
_debugText.text += "Damage: " + mm.damage + "opaque: " + mm.opaque;
}
}
}
Thanks for reading and any help!
try this
if(!string.IsNullOrEmpty(minimap)
{
minimap[][] minimaps = JsonUtility.FromJson<minimaps[][]>(minimap);
if(minimaps!=null)
{
foreach (var mms in minimaps)
{
if(mms==null) _debugText.text ="Error: mms is null";
else
foreach (minimap mm in mms)
_debugText.text += "Damage: " + mm.damage + "opaque: " + mm.opaque;
}
}
} else _debugText.text ="Error: minimaps is null";
} else _debugText.text ="Error: minimap is an empty string";
but I highly recommend you to google and istall Newtonsoft.Json for Unity3d
using Newtonsoft.Json;
minimap[][] minimaps = JsonConvert.DeserializeObject<minimaps[][]>(minimap);

Adding aspnet-api-versioning prevents UrlHelper from generating Controller API routes within a Razor Pages request

I can create a file->new aspnetcore API project and use the IUrlHelper to generate a route by name without any issues.
[Route("api/[controller]")]
public class ValuesController : Controller
{
public const string GetValues = "GetValues";
public const string GetValuesById = "GetValuesById";
public static string[] Values = new[] { "value1", "value2", "value3", };
// GET api/values
[HttpGet(Name = GetValues)]
public IEnumerable<object> Get()
{
var result = new List<object>();
for(int index = 0; index < Values.Length - 1; index++)
{
string routeForElement = this.Url.RouteUrl(GetValuesById, new { Id = index });
result.Add(new { Value = Values[index], Route = routeForElement });
}
return result;
}
// GET api/values/5
[HttpGet("{id}", Name = GetValuesById)]
public string Get(int id)
{
if (id > (Values.Length - 1))
{
return "Invalid Id";
}
return Values[id];
}
}
When the response is sent back, I correctly have the routes that I've created:
[
{
"value": "value1",
"route": "/api/v1/Values/0"
},
{
"value": "value2",
"route": "/api/v1/Values/1"
},
{
"value": "value3",
"route": "/api/v1/Values/2"
}
]
I can then use the Visual Studio Scaffolding to create a Razor Page and continue to generate the same route without any issues within my Razor Page:
Model
public class IndexModel : PageModel
{
public List<string> Routes { get; set; } = new List<string>();
public void OnGet()
{
for (int index = 0; index < ValuesController.Values.Length; index++)
{
string routeForElement = this.Url.RouteUrl(ValuesController.GetValuesById, new { Id = index });
Routes.Add(routeForElement);
}
}
}
Page
#page
#model UrlHelperWithPages.Pages.IndexModel
#foreach(string route in Model.Routes)
{
<h4>#route</h4>
}
This renders the routes without issue.
If I add the aspnet-api-versioning nuget package and configure it's services:
services.AddApiVersioning();
My API controller continues to work with the following modification. Any request that is destined for this controller has the routes generated correctly.
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class ValuesController : Controller
However the Razor Pages stops working when we try to generate a route from within a Razor Pages request. The RouteUrl method now returns null. I've tried updating the route data provided to the RouteUrl method so that I pass a hard-coded version (for testing) and it doesn't work either.
new { version = 1, Id = index }
Is there any configuration that needs to happen on the api versioning package to support pages? We have razor pages that we want to generate API routes for rendering in the page, but it doesn't seem to work.

Windows Phone 8 ImageSource cannot be serialized Error while sharing image

i am trying to share an image. I got a picture object and am getting the path from it. When I'm calling the ShareMediaTask it throw following error:
System.Windows.Media.ImageSource cannot be serialized.
I am still able to share the image, but the app crashes when returning from sharing.
Here is my code:
PictureModel picture = Singleton.Instance.BearPicture.Model.Images.Where(PictureModel => PictureModel.Bmp.UriSource == (Image_View.Source as BitmapImage).UriSource).FirstOrDefault();
var task = new ShareMediaTask();
task.FilePath = picture.Picture.GetPath();
task.Show();
My PictureModel looks like this:
public class PictureModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _uri;
public string Uri
{
get { return _uri; }
set
{
if (value != _uri)
{
_uri = value;
NotifyPropertyChanged("Uri");
}
}
}
private string _relativePath;
public string RelativePath
{
get { return _relativePath; }
set
{
if (_relativePath != value)
{
_relativePath = value;
NotifyPropertyChanged("RelativePath");
}
}
}
private BitmapImage _bmp;
public BitmapImage Bmp
{
get { return _bmp; }
set
{
if (value != _bmp)
{
_bmp = value;
NotifyPropertyChanged("Bmp");
}
}
}
private Picture _picture;
public Picture Picture
{
get { return _picture; }
set
{
if (value != _picture)
{
_picture = value;
NotifyPropertyChanged("Picture");
}
}
}
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Where does this error come from? I am only getting the Source of my image object but i am not doing anything else with it. My picture is also saved in the media library like this:
myFileStream = myStore.OpenFile(fileName, FileMode.Open, FileAccess.Read);
MediaLibrary library = new MediaLibrary();
Picture pic = library.SavePicture(fileName, myFileStream);
On Appstart im searching through my savedpicture folder, to get the picture object, which is then saved in my PictureModel.
Any help is appreciated.
Thanks in advance.
robidd
This may help: Crashes Back (WriteableBitmap cannot be serialized) windows phone 8. See the comment from KooKiz.
"Same symptoms, same cause. You've stored at some point an ImageSource in the phone state (probably PhoneApplicationService.Current.State or IsolatedStorageSettings.ApplicationSettings). You have to find where!"
Apparently we can cause this error indirectly. I'm having a similar problem and I found that answer and also your own question.
Hope it helps.
Cheers.

Bind to action method

Is it possible to use a simple action method - just like with Caliburn.Micro - instead of a command with MvvmCross bindings?
Example:
public void Action()
{
Tip = 11;
}
<Button
android:text="Button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/button1"
local:MvxBind="Click Action" />
It doesn't work out of the box, I tested that.
While I found a lot of samples about adding new target bindings, I didn't find a single one about adding a new source binding.
UPDATE:
This works now out of the box with the Rio binding. To use it, add the MvvmCross MethodBinding NuGet package to the Android project.
Up until now, much of the emphasis for MvvmCross has been on allowing multi-platform target binding with the source remaining mainly 'vanilla' INotifyPropertyChanged.
There have been some deviation in terms of ViewModel structure - e.g.:
the MvxCommandCollection - http://slodge.blogspot.co.uk/2013/03/fixing-mvvm-commands-making-hot-tuna.html
some users using Fody - http://twincoders.com/blog/codigo-limpio-con-fody/
Recently, several new feature requests have also been logged in this area:
AutoCommands - I think this is what you are asking about here - https://github.com/slodge/MvvmCross/issues/301
Rio binding sources - https://github.com/slodge/MvvmCross/issues/299
Tibet binding - https://github.com/slodge/MvvmCross/issues/298
Because of these, I do expect more functionality to be exposed in this area in the future...
With that said, if you wanted to get this working today, then MvvmCross Binding is overrideable so you could fairly easily do it:
1. Implement an ICommand that invokes a MethodInfo using reflection (for completeness this should probably also use a parameter if available) - some kind of InvokeMethodCommand (code for this left to the reader!)
.
2. Implement an MyMethodSourceBinding class which wraps the InvokeMethodCommand - something like:
public class MyMethodSourceBinding : MvxSourceBinding
{
private readonly MethodInfo _methodInfo;
protected MyMethodSourceBinding(object source, MethodInfo methodInfo)
: base(source)
{
_methodInfo = _methodInfo;
}
public override void SetValue(object value)
{
// do nothing - not allowed
}
public override Type SourceType
{
get { return typeof(ICommand); }
}
public override bool TryGetValue(out object value)
{
value = new InvokeMethodCommand(source, _methodInfo);
return true;
}
}
3. Override MvvmCross's registered IMvxSourceBindingFactory with your own implementation that can detect when a method is present - sadly most of this is cut and paste coding today - it would be something like
public class MySourceBindingFactory
: IMvxSourceBindingFactory
{
private IMvxSourcePropertyPathParser _propertyPathParser;
private IMvxSourcePropertyPathParser SourcePropertyPathParser
{
get
{
if (_propertyPathParser == null)
{
_propertyPathParser = Mvx.Resolve<IMvxSourcePropertyPathParser>();
}
return _propertyPathParser;
}
}
public IMvxSourceBinding CreateBinding(object source, string combinedPropertyName)
{
var tokens = SourcePropertyPathParser.Parse(combinedPropertyName);
return CreateBinding(source, tokens);
}
public IMvxSourceBinding CreateBinding(object source, IList<MvxPropertyToken> tokens)
{
if (tokens == null || tokens.Count == 0)
{
throw new MvxException("empty token list passed to CreateBinding");
}
var currentToken = tokens[0];
if (tokens.Count == 1)
{
return CreateLeafBinding(source, currentToken);
}
else
{
var remainingTokens = tokens.Skip(1).ToList();
return CreateChainedBinding(source, currentToken, remainingTokens);
}
}
private static MvxChainedSourceBinding CreateChainedBinding(object source, MvxPropertyToken propertyToken,
List<MvxPropertyToken> remainingTokens)
{
if (propertyToken is MvxIndexerPropertyToken)
{
return new MvxIndexerChainedSourceBinding(source, (MvxIndexerPropertyToken) propertyToken,
remainingTokens);
}
else if (propertyToken is MvxPropertyNamePropertyToken)
{
return new MvxSimpleChainedSourceBinding(source, (MvxPropertyNamePropertyToken) propertyToken,
remainingTokens);
}
throw new MvxException("Unexpected property chaining - seen token type {0}",
propertyToken.GetType().FullName);
}
private static IMvxSourceBinding CreateLeafBinding(object source, MvxPropertyToken propertyToken)
{
if (propertyToken is MvxIndexerPropertyToken)
{
return new MvxIndexerLeafPropertyInfoSourceBinding(source, (MvxIndexerPropertyToken) propertyToken);
}
else if (propertyToken is MvxPropertyNamePropertyToken)
{
//**************************
// Special code is here
var propertyToken = (MvxPropertyNamePropertyToken) propertyToken;
if (source != null)
{
var method = source.GetType().GetMethod(propertyToken.PropertyName, BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);
if (method != null)
{
return new MyMethodSourceBinding(source, method);
}
}
return new MvxSimpleLeafPropertyInfoSourceBinding(source,
(MvxPropertyNamePropertyToken) propertyToken);
// Special code ends here
//**************************
}
else if (propertyToken is MvxEmptyPropertyToken)
{
return new MvxDirectToSourceBinding(source);
}
throw new MvxException("Unexpected property source - seen token type {0}", propertyToken.GetType().FullName);
}
}
4. Supply this source binding factory in your own custom binding builder - e.g.:
public class MyAndroidBindingBuilder
: MvxAndroidBindingBuilder
{
protected override IMvxSourceBindingFactory CreateSourceBindingFactory()
{
return new MvxSourceBindingFactory();
}
}
5. Supply this binding builder during your setup
public class Setup : MvxAndroidSetup
{
// ....
protected override MvxAndroidBindingBuilder CreateBindingBuilder()
{
return new MyAndroidBindingBuilder();
}
}
Note: This approach is only for advanced users right now... As suggested in the first part of this question, I do expect the code in this area to change quite a lot so you might also encounter some issues maintaining a fork in this area. (Indeed the code in this area has already changed quite significantly on the Tibet Binding branch within the GitHub repo!)

SWT JFace: SelectionProvider not working in TabFolder

In a GraphicalEditor I created a tab folder:
private final String[] tabNames = { "Text", "Image" };
private ResourcesTextComposite comText;
private ResourcesImageComposite comImage;
...
public void createPartControl(Composite parent) {
...
tabFolder = new TabFolder(parent, SWT.BORDER);
for (int loopIndex = 0; loopIndex < tabNames.length; loopIndex++) {
TabItem tabItem = new TabItem(tabFolder, SWT.NULL);
tabItem.setText(tabNames[loopIndex]);
if (loopIndex == 0) {
comText = new ResourcesTextComposite(tabFolder, SWT.NONE,
resources);
tabItem.setControl(comText);
} else if (loopIndex == 1) {
comImage = new ResourcesImageComposite(tabFolder, SWT.NONE,
resources);
tabItem.setControl(comImage);
}
}
...
}
it has 2 tab items and each item has a composite in it, and each composite has a TableViewer respectively.
I tried this to make each TableViewer the selection provider when the user selects the corresponding tab item (the same function createPartControl of the editor):
public void createPartControl(Composite parent) {
...
tabFolder.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
int tabIdx = tabFolder.getSelectionIndex();
getSite().setSelectionProvider(null);
if (tabIdx == 0) {
getSite().setSelectionProvider(comText.getViewer());
} else if (tabIdx == 1) {
getSite().setSelectionProvider(comImage.getViewer());
}
System.out.println("widgetSelected" + getSite() + ": "
+ getSite().getSelectionProvider());
}
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
});
...
}
I hope when I select a row in a TableViewer, the Properties view will show the selected model's properties, I've complete those IPropertySource things and they works well in other editors that has no tab folders, so I think the problem should be in the Selection Provider area.
Any ideas or has anyone encountered the same problem?
If you have multiple selection providers in a view or editor, then you need to use a mediator like org.eclipse.jdt.internal.ui.viewsupport.SelectionProviderMediator. Note that it is unfortunately internal, so you need to copy it to your own project