string template = "Hello #Model.Name, welcome to RazorEngine!";
var result = Engine.Razor.RunCompile(template, "templateKey", null, new { Name = "World" });
Now i update my existing template to as below. I get my template from database.
string template = "Hello #Model.Name, welcome to My World!";
Whenever i do that i get an error The same key was already used for another template.
What is the best way to fix this issue?
The issue is that you are not using a template key that is unique to the template code you are passing in. RazorEngine caches the templates and compiles them so the next time round it's faster to run.
var helloTemplate = "Hello #Model.Name";
string result;
var model = new { Name = "World" };
//Has the template already been used? If so, Run without compilation is faster
if(Engine.Razor.IsTemplateCached("helloTemplate", null))
{
result = Engine.Razor.Run("helloTemplate", null, model);
}
else
{
result = Engine.Razor.RunCompile(helloTemplate, "helloTemplate", null, model);
}
Related
I'm trying to make a targetingIdeaService API call to Google AdWords. This is my code so far:
[HttpGet]
public IEnumerable<string> Get()
{
var user = new AdWordsUser();
using (TargetingIdeaService targetingIdeaService = (TargetingIdeaService)user.GetService(AdWordsService.v201802.TargetingIdeaService))
{
// Create selector.
TargetingIdeaSelector selector = new TargetingIdeaSelector();
selector.requestType = RequestType.IDEAS;
selector.ideaType = IdeaType.KEYWORD;
selector.requestedAttributeTypes = new AttributeType[] {
AttributeType.KEYWORD_TEXT,
AttributeType.SEARCH_VOLUME,
AttributeType.AVERAGE_CPC,
AttributeType.COMPETITION,
AttributeType.CATEGORY_PRODUCTS_AND_SERVICES
};
// Set selector paging (required for targeting idea service).
var paging = Paging.Default;
// Create related to query search parameter.
var relatedToQuerySearchParameter =
new RelatedToQuerySearchParameter
{ queries = new String[] { "bakery", "pastries", "birthday cake" } };
var searchParameters = new List<SearchParameter> { relatedToQuerySearchParameter };
var page = new TargetingIdeaPage();
page = targetingIdeaService.get(selector);
return new string[] { "value1", "value2" };
}
}
it looks ok, compiles at last, and so on. But then I went into debug mode. And I saw this:
So as you can see, the variable doesn't have the access token. The other data comes from app.config file.
I am quite certain the keys passed in are correct.
Then the code throws the famous invalid_grand error. In my case, I believe that's because the access token is not being generated. I'm new to AdWords and ASP.NET, so I probably missed something, but I have no idea what.
I used the
docs,
Code Structure instructions, and
code examples to put it all together.
I had my configuration wrong. I had to recreate all the credentials using incognito window. If you have any issues just open a thread here: https://groups.google.com/forum/#!forum/adwords-api
I'm trying to query the search API of Rally, here is my c# code:
var searchRequest = new Request()
{
ArtifactName = "search",
Limit = 25,
Project = "/project/" + CurrentProject,
ProjectScopeDown = true,
ProjectScopeUp = true,
PageSize = 25,
Fetch = new List<string>() { "true" }
};
searchRequest.AddParameter("keywords", "foo");
QueryResult queryTaskResult = api.Query(searchRequest);
this works as expected and returns result, however i want to pass a parameter of compact=true, which will return slightly different data (mainly a standard web link to the item).
var searchRequest = new Request()
{
ArtifactName = "search",
Limit = 25,
Project = "/project/" + CurrentProject,
ProjectScopeDown = true,
ProjectScopeUp = true,
PageSize = 25,
Fetch = new List<string>() { "true" }
};
searchRequest.AddParameter("keywords", "foo");
///this is the new item
searchRequest.AddParameter("compact", "true");
QueryResult queryTaskResult = api.Query(searchRequest);
However when i fire this request I get the following error
Rally.RestApi.Json.DynamicJsonObject' does not contain a definition for 'Errors'
However when I try to do this request in the browser it works fine.
Any help as to what I'm doing wrong would be greatly appreciated!
Why do you want to do this?
What I want to do is build up a link to the WEB view of the object, eg:
https://rally1.rallydev.com/#/{CurrentProject}d/detail/{ObjectType}/{ObjectId}
I already know the CurrentProject, I need to know the ObjectType and the ObjectId
I have found, when i pass compact=true, the _ref provides this, '/defect/1234567' but this throws an exception.
If I do not pass compact=true, the _ref returns the API reference 'https://rally1.rallydev.com/slm/webservice/v2.x/defect/1234567'
Unfortunately the compact functionality was added to WSAPI after the .NET toolkit was created and we've never updated it to support it.
I filed a github issue here: https://github.com/RallyTools/RallyRestToolkitFor.NET/issues/37
compact=true was mainly a performance optimization to reduce the size of responses in large result sets.
Other than performance is there a reason you'd like to use it?
I'm using the latest version of razor from.
https://github.com/Antaris/RazorEngine
I want to attached it to some cshtml and debug against it.
The readme states the following
Debugging
One thing you might want to enable is the debugging feature:
config.Debug = true;
When Debug is true you can straight up debug into the generated code. RazorEngine also supports debugging directly into the
template files (normally .cshtml files). As as you might see in the
above code there is no file to debug into. To provide RazorEngine with
the necessary information you need to tell where the file can be
found:
string template = "Hello #Model.Name, welcome to RazorEngine!";
string templateFile = "C:/mytemplate.cshtml"
var result = Engine.Razor.RunCompile(new LoadedTemplateSource(template, templateFile), "templateKey", null, new {
In my code i have setup the following
var config = new TemplateServiceConfiguration();
// .. configure your instance
config.Debug = true;
var service = RazorEngineService.Create(config);
Engine.Razor = service;
//string template = "Hello #Model.Name, welcome to RazorEngine!";
string templateFile = "C:/mytemplate.cshtml";
var template = new LoadedTemplateSource("", templateFile);
var result = Engine.Razor.RunCompile(template, this.Name, null, model);
Now I have created a cshtml file at that path with the following in it.
#{
var a = 1;
a = a + a;
#a
}
<div>
hi
</div>
But I get returned an empty string :(
And when i f11 into it it just steps over :( :(.
Im not sure what im doing wrong anyone got any ideas.
Answer code
string templateFile = "C:/mytemplate.cshtml";
StringBuilder sb = new StringBuilder();
using (StreamReader sr = new StreamReader(templateFile))
{
String line;
// Read and display lines from the file until the end of
// the file is reached.
while ((line = sr.ReadLine()) != null)
{
sb.AppendLine(line);
}
}
string allines = sb.ToString();
var template = new LoadedTemplateSource(allines, templateFile);
var result = Engine.Razor.RunCompile(template, this.Name, null, model);
The LoadedTemplateSource represents the template source code, and you have given "" as the source code, therefore your template is empty.
The first parameter of LoadedTemplateSource needs to be the source code of the template and the second one is the path to the file, which is only used for debugging purposes.
If you need lazy loading or a custom loader strategy you can either implement a custom ITemplateSource or ITemplateManager, however having the source available in memory all time improves some error messages as well.
matthid, a RazorEngine Contributor
Disabling "Enable Just My Code" in Options > Debugging > General worked for me.
Using MvcMailer, the problem is that our emails are being sent without our CSS as inline style attributes.
PreMailer.Net is a C# Library that can read in an HTML source string, and return a resultant HTML string with CSS in-lined.
How do we use them together? Using the scaffolding example in the MvcMailer step-by-step guide, we start out with this example method in our UserMailer Mailer class:
public virtual MvcMailMessage Welcome()
{
return Populate(x => {
x.ViewName = "Welcome";
x.To.Add("some-email#example.com");
x.Subject = "Welcome";
});
}
Simply install PreMailer.Net via NugGet
Update the Mailer class:
public virtual MvcMailMessage Welcome()
{
var message = Populate(x => {
x.ViewName = "Welcome";
x.To.Add("some-email#example.com");
x.Subject = "Welcome";
});
message.Body = PreMailer.Net.PreMailer.MoveCssInline(message.Body).Html;
return message;
}
Done!
If you have a text body with HTML as an alternate view (which I recommend) you'll need to do the following:
var message = Populate(m =>
{
m.Subject = subject;
m.ViewName = viewName;
m.To.Add(model.CustomerEmail);
m.From = new System.Net.Mail.MailAddress(model.FromEmail);
});
// get the BODY so we can process it
var body = EmailBody(message.ViewName);
var processedBody = PreMailer.Net.PreMailer.MoveCssInline(body, true).Html;
// start again with alternate view
message.AlternateViews.Clear();
// add BODY as alternate view
var htmlView = AlternateView.CreateAlternateViewFromString(processedBody, new ContentType("text/html"));
message.AlternateViews.Add(htmlView);
// add linked resources to the HTML view
PopulateLinkedResources(htmlView, message.LinkedResources);
Note: Even if you think you don't care about text it can help with spam filters.
I recommend reading the source for MailerBase to get a better idea what's going on cos all these Populate methods get confusing.
Note: This may not run as-is but you get the idea. I have code (not shown) that parses for any img tags and adds as auto attachments.
Important part is to clear the HTML alternate view. You must have a .text.cshtml file for the text view.
If you're using ActionMailer.Net(.Next), you can do this:
protected override void OnMailSending(MailSendingContext context)
{
if (context.Mail.IsBodyHtml)
{
var inlineResult = PreMailer.Net.PreMailer.MoveCssInline(context.Mail.Body);
context.Mail.Body = inlineResult.Html;
}
for (var i = 0; i < context.Mail.AlternateViews.Count; i++)
{
var alternateView = context.Mail.AlternateViews[i];
if (alternateView.ContentType.MediaType != AngleSharp.Network.MimeTypeNames.Html) continue;
using (alternateView) // make sure it is disposed
{
string content;
using (var reader = new StreamReader(alternateView.ContentStream))
{
content = reader.ReadToEnd();
}
var inlineResult = PreMailer.Net.PreMailer.MoveCssInline(content);
context.Mail.AlternateViews[i] = AlternateView.CreateAlternateViewFromString(inlineResult.Html, alternateView.ContentType);
}
}
base.OnMailSending(context);
}
If you don't like using AngleSharp.Network.MimeTypeNames, you can just use "text/html". AngleSharp comes as a dependency of ActionMailer.Net.
I am performing an insert operation with Entity Framework 5.
My code inserts a new row from a user input and parsed values in another method. The debug operation shows all object attributes have a value before the insert operation is called, the code executes without any exception, and the row is updated in the LocalDb, but content column value is missing or never saved.
Here is my entity framework code:
public async Task<IHttpActionResult> PostFormData()
{
var profile = db.ProfileRepository.dbSet.Where(m => m.profileId == 1).FirstOrDefaultAsync().Result;
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var research = new Research();
research.profile = profile;
string root = HttpContext.Current.Server.MapPath("~/documentSafe");
var provider = new MultipartFormDataStreamProvider(root);
try
{
// Read the form data.
await Request.Content.ReadAsMultipartAsync(provider);
research.title = provider.FormData["title"];
research.researchAbstract = provider.FormData["researchAbstract"];
research.publisher = provider.FormData["publisher"];
var areaList = new List<ResearchArea>();
string areas = provider.FormData["researchArea"];
foreach (var r in areas.Split(','))
{
var area = new ResearchArea()
{
name = r,
departmentId = profile.departmentId
};
areaList.Add(area);
}
research.researchArea = areaList;
research.researchType = new ResearchType()
{
name = provider.FormData["type"]
};
string content = WebUtility.HtmlEncode(parser.convert(provider.FileData[0]));
research.content = content;
using (var context = new AcademicContext())
{
context.Research.Add(research);
await context.SaveChangesAsync();
}
return Ok();
}
catch (System.Exception e)
{
return InternalServerError(e);
}
}
The missing column is a parsed html string encoded using webutility and has an average size of 15,000 characters. I have checked the database column attribute too, and it is set to nvarchar(MAX).
If I insert a sample plain text to the column, the value get saved, but if I pass the encoded html string it does not.
Any suggestions why my column will not be null but still not contain any value.
Solution: The sql server explorer in visual studio seem to display an empty column when the character size is greater than 4000. I ran multiple test to verity this. I could get the content of the empty column by running raw sql select query.